mercurial/thirdparty/attr/_make.py
author Gregory Szorc <gregory.szorc@gmail.com>
Mon, 24 Sep 2018 14:31:31 -0700
changeset 39878 3e896b51aa5d
parent 34397 765eb17a7eb8
child 41564 a5493a251ad3
permissions -rw-r--r--
storageutil: move metadata parsing and packing from revlog (API) Parsing and writing of revision text metadata is likely identical across storage backends. Let's move the code out of revlog so we don't need to import the revlog module in order to use it. Differential Revision: https://phab.mercurial-scm.org/D4754
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
34397
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     1
from __future__ import absolute_import, division, print_function
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     2
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     3
import hashlib
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     4
import linecache
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     5
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     6
from operator import itemgetter
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     7
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     8
from . import _config
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
     9
from ._compat import PY2, iteritems, isclass, iterkeys, metadata_proxy
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    10
from .exceptions import (
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    11
    DefaultAlreadySetError,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    12
    FrozenInstanceError,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    13
    NotAnAttrsClassError,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    14
)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    15
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    16
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    17
# This is used at least twice, so cache it here.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    18
_obj_setattr = object.__setattr__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    19
_init_convert_pat = "__attr_convert_{}"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    20
_init_factory_pat = "__attr_factory_{}"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    21
_tuple_property_pat = "    {attr_name} = property(itemgetter({index}))"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    22
_empty_metadata_singleton = metadata_proxy({})
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    23
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    24
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    25
class _Nothing(object):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    26
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    27
    Sentinel class to indicate the lack of a value when ``None`` is ambiguous.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    28
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    29
    All instances of `_Nothing` are equal.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    30
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    31
    def __copy__(self):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    32
        return self
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    33
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    34
    def __deepcopy__(self, _):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    35
        return self
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    36
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    37
    def __eq__(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    38
        return other.__class__ == _Nothing
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    39
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    40
    def __ne__(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    41
        return not self == other
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    42
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    43
    def __repr__(self):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    44
        return "NOTHING"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    45
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    46
    def __hash__(self):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    47
        return 0xdeadbeef
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    48
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    49
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    50
NOTHING = _Nothing()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    51
"""
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    52
Sentinel to indicate the lack of a value when ``None`` is ambiguous.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    53
"""
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    54
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    55
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    56
def attr(default=NOTHING, validator=None,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    57
         repr=True, cmp=True, hash=None, init=True,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    58
         convert=None, metadata={}):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    59
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    60
    Create a new attribute on a class.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    61
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    62
    ..  warning::
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    63
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    64
        Does *not* do anything unless the class is also decorated with
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    65
        :func:`attr.s`!
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    66
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    67
    :param default: A value that is used if an ``attrs``-generated ``__init__``
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    68
        is used and no value is passed while instantiating or the attribute is
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    69
        excluded using ``init=False``.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    70
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    71
        If the value is an instance of :class:`Factory`, its callable will be
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    72
        used to construct a new value (useful for mutable datatypes like lists
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    73
        or dicts).
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    74
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    75
        If a default is not set (or set manually to ``attr.NOTHING``), a value
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    76
        *must* be supplied when instantiating; otherwise a :exc:`TypeError`
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    77
        will be raised.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    78
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    79
        The default can also be set using decorator notation as shown below.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    80
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    81
    :type default: Any value.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    82
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    83
    :param validator: :func:`callable` that is called by ``attrs``-generated
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    84
        ``__init__`` methods after the instance has been initialized.  They
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    85
        receive the initialized instance, the :class:`Attribute`, and the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    86
        passed value.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    87
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    88
        The return value is *not* inspected so the validator has to throw an
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    89
        exception itself.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    90
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    91
        If a ``list`` is passed, its items are treated as validators and must
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    92
        all pass.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    93
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    94
        Validators can be globally disabled and re-enabled using
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    95
        :func:`get_run_validators`.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    96
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    97
        The validator can also be set using decorator notation as shown below.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    98
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
    99
    :type validator: ``callable`` or a ``list`` of ``callable``\ s.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   100
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   101
    :param bool repr: Include this attribute in the generated ``__repr__``
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   102
        method.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   103
    :param bool cmp: Include this attribute in the generated comparison methods
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   104
        (``__eq__`` et al).
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   105
    :param hash: Include this attribute in the generated ``__hash__``
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   106
        method.  If ``None`` (default), mirror *cmp*'s value.  This is the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   107
        correct behavior according the Python spec.  Setting this value to
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   108
        anything else than ``None`` is *discouraged*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   109
    :type hash: ``bool`` or ``None``
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   110
    :param bool init: Include this attribute in the generated ``__init__``
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   111
        method.  It is possible to set this to ``False`` and set a default
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   112
        value.  In that case this attributed is unconditionally initialized
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   113
        with the specified default value or factory.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   114
    :param callable convert: :func:`callable` that is called by
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   115
        ``attrs``-generated ``__init__`` methods to convert attribute's value
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   116
        to the desired format.  It is given the passed-in value, and the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   117
        returned value will be used as the new value of the attribute.  The
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   118
        value is converted before being passed to the validator, if any.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   119
    :param metadata: An arbitrary mapping, to be used by third-party
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   120
        components.  See :ref:`extending_metadata`.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   121
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   122
    ..  versionchanged:: 17.1.0 *validator* can be a ``list`` now.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   123
    ..  versionchanged:: 17.1.0
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   124
        *hash* is ``None`` and therefore mirrors *cmp* by default .
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   125
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   126
    if hash is not None and hash is not True and hash is not False:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   127
        raise TypeError(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   128
            "Invalid value for hash.  Must be True, False, or None."
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   129
        )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   130
    return _CountingAttr(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   131
        default=default,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   132
        validator=validator,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   133
        repr=repr,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   134
        cmp=cmp,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   135
        hash=hash,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   136
        init=init,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   137
        convert=convert,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   138
        metadata=metadata,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   139
    )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   140
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   141
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   142
def _make_attr_tuple_class(cls_name, attr_names):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   143
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   144
    Create a tuple subclass to hold `Attribute`s for an `attrs` class.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   145
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   146
    The subclass is a bare tuple with properties for names.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   147
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   148
    class MyClassAttributes(tuple):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   149
        __slots__ = ()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   150
        x = property(itemgetter(0))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   151
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   152
    attr_class_name = "{}Attributes".format(cls_name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   153
    attr_class_template = [
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   154
        "class {}(tuple):".format(attr_class_name),
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   155
        "    __slots__ = ()",
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   156
    ]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   157
    if attr_names:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   158
        for i, attr_name in enumerate(attr_names):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   159
            attr_class_template.append(_tuple_property_pat.format(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   160
                index=i,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   161
                attr_name=attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   162
            ))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   163
    else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   164
        attr_class_template.append("    pass")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   165
    globs = {"itemgetter": itemgetter}
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   166
    eval(compile("\n".join(attr_class_template), "", "exec"), globs)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   167
    return globs[attr_class_name]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   168
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   169
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   170
def _transform_attrs(cls, these):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   171
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   172
    Transforms all `_CountingAttr`s on a class into `Attribute`s and saves the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   173
    list in `__attrs_attrs__`.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   174
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   175
    If *these* is passed, use that and don't look for them on the class.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   176
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   177
    super_cls = []
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   178
    for c in reversed(cls.__mro__[1:-1]):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   179
        sub_attrs = getattr(c, "__attrs_attrs__", None)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   180
        if sub_attrs is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   181
            super_cls.extend(a for a in sub_attrs if a not in super_cls)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   182
    if these is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   183
        ca_list = [(name, attr)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   184
                   for name, attr
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   185
                   in cls.__dict__.items()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   186
                   if isinstance(attr, _CountingAttr)]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   187
    else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   188
        ca_list = [(name, ca)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   189
                   for name, ca
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   190
                   in iteritems(these)]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   191
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   192
    non_super_attrs = [
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   193
        Attribute.from_counting_attr(name=attr_name, ca=ca)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   194
        for attr_name, ca
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   195
        in sorted(ca_list, key=lambda e: e[1].counter)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   196
    ]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   197
    attr_names = [a.name for a in super_cls + non_super_attrs]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   198
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   199
    AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   200
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   201
    cls.__attrs_attrs__ = AttrsClass(super_cls + [
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   202
        Attribute.from_counting_attr(name=attr_name, ca=ca)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   203
        for attr_name, ca
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   204
        in sorted(ca_list, key=lambda e: e[1].counter)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   205
    ])
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   206
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   207
    had_default = False
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   208
    for a in cls.__attrs_attrs__:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   209
        if these is None and a not in super_cls:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   210
            setattr(cls, a.name, a)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   211
        if had_default is True and a.default is NOTHING and a.init is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   212
            raise ValueError(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   213
                "No mandatory attributes allowed after an attribute with a "
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   214
                "default value or factory.  Attribute in question: {a!r}"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   215
                .format(a=a)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   216
            )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   217
        elif had_default is False and \
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   218
                a.default is not NOTHING and \
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   219
                a.init is not False:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   220
            had_default = True
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   221
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   222
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   223
def _frozen_setattrs(self, name, value):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   224
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   225
    Attached to frozen classes as __setattr__.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   226
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   227
    raise FrozenInstanceError()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   228
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   229
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   230
def _frozen_delattrs(self, name):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   231
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   232
    Attached to frozen classes as __delattr__.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   233
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   234
    raise FrozenInstanceError()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   235
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   236
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   237
def attributes(maybe_cls=None, these=None, repr_ns=None,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   238
               repr=True, cmp=True, hash=None, init=True,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   239
               slots=False, frozen=False, str=False):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   240
    r"""
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   241
    A class decorator that adds `dunder
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   242
    <https://wiki.python.org/moin/DunderAlias>`_\ -methods according to the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   243
    specified attributes using :func:`attr.ib` or the *these* argument.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   244
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   245
    :param these: A dictionary of name to :func:`attr.ib` mappings.  This is
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   246
        useful to avoid the definition of your attributes within the class body
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   247
        because you can't (e.g. if you want to add ``__repr__`` methods to
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   248
        Django models) or don't want to.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   249
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   250
        If *these* is not ``None``, ``attrs`` will *not* search the class body
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   251
        for attributes.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   252
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   253
    :type these: :class:`dict` of :class:`str` to :func:`attr.ib`
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   254
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   255
    :param str repr_ns: When using nested classes, there's no way in Python 2
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   256
        to automatically detect that.  Therefore it's possible to set the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   257
        namespace explicitly for a more meaningful ``repr`` output.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   258
    :param bool repr: Create a ``__repr__`` method with a human readable
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   259
        represantation of ``attrs`` attributes..
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   260
    :param bool str: Create a ``__str__`` method that is identical to
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   261
        ``__repr__``.  This is usually not necessary except for
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   262
        :class:`Exception`\ s.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   263
    :param bool cmp: Create ``__eq__``, ``__ne__``, ``__lt__``, ``__le__``,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   264
        ``__gt__``, and ``__ge__`` methods that compare the class as if it were
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   265
        a tuple of its ``attrs`` attributes.  But the attributes are *only*
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   266
        compared, if the type of both classes is *identical*!
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   267
    :param hash: If ``None`` (default), the ``__hash__`` method is generated
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   268
        according how *cmp* and *frozen* are set.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   269
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   270
        1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   271
        2. If *cmp* is True and *frozen* is False, ``__hash__`` will be set to
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   272
           None, marking it unhashable (which it is).
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   273
        3. If *cmp* is False, ``__hash__`` will be left untouched meaning the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   274
           ``__hash__`` method of the superclass will be used (if superclass is
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   275
           ``object``, this means it will fall back to id-based hashing.).
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   276
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   277
        Although not recommended, you can decide for yourself and force
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   278
        ``attrs`` to create one (e.g. if the class is immutable even though you
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   279
        didn't freeze it programmatically) by passing ``True`` or not.  Both of
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   280
        these cases are rather special and should be used carefully.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   281
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   282
        See the `Python documentation \
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   283
        <https://docs.python.org/3/reference/datamodel.html#object.__hash__>`_
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   284
        and the `GitHub issue that led to the default behavior \
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   285
        <https://github.com/python-attrs/attrs/issues/136>`_ for more details.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   286
    :type hash: ``bool`` or ``None``
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   287
    :param bool init: Create a ``__init__`` method that initialiazes the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   288
        ``attrs`` attributes.  Leading underscores are stripped for the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   289
        argument name.  If a ``__attrs_post_init__`` method exists on the
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   290
        class, it will be called after the class is fully initialized.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   291
    :param bool slots: Create a slots_-style class that's more
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   292
        memory-efficient.  See :ref:`slots` for further ramifications.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   293
    :param bool frozen: Make instances immutable after initialization.  If
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   294
        someone attempts to modify a frozen instance,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   295
        :exc:`attr.exceptions.FrozenInstanceError` is raised.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   296
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   297
        Please note:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   298
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   299
            1. This is achieved by installing a custom ``__setattr__`` method
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   300
               on your class so you can't implement an own one.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   301
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   302
            2. True immutability is impossible in Python.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   303
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   304
            3. This *does* have a minor a runtime performance :ref:`impact
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   305
               <how-frozen>` when initializing new instances.  In other words:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   306
               ``__init__`` is slightly slower with ``frozen=True``.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   307
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   308
            4. If a class is frozen, you cannot modify ``self`` in
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   309
               ``__attrs_post_init__`` or a self-written ``__init__``. You can
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   310
               circumvent that limitation by using
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   311
               ``object.__setattr__(self, "attribute_name", value)``.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   312
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   313
        ..  _slots: https://docs.python.org/3.5/reference/datamodel.html#slots
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   314
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   315
    ..  versionadded:: 16.0.0 *slots*
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   316
    ..  versionadded:: 16.1.0 *frozen*
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   317
    ..  versionadded:: 16.3.0 *str*, and support for ``__attrs_post_init__``.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   318
    ..  versionchanged::
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   319
            17.1.0 *hash* supports ``None`` as value which is also the default
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   320
            now.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   321
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   322
    def wrap(cls):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   323
        if getattr(cls, "__class__", None) is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   324
            raise TypeError("attrs only works with new-style classes.")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   325
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   326
        if repr is False and str is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   327
            raise ValueError(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   328
                "__str__ can only be generated if a __repr__ exists."
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   329
            )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   330
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   331
        if slots:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   332
            # Only need this later if we're using slots.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   333
            if these is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   334
                ca_list = [name
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   335
                           for name, attr
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   336
                           in cls.__dict__.items()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   337
                           if isinstance(attr, _CountingAttr)]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   338
            else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   339
                ca_list = list(iterkeys(these))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   340
        _transform_attrs(cls, these)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   341
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   342
        # Can't just re-use frozen name because Python's scoping. :(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   343
        # Can't compare function objects because Python 2 is terrible. :(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   344
        effectively_frozen = _has_frozen_superclass(cls) or frozen
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   345
        if repr is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   346
            cls = _add_repr(cls, ns=repr_ns)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   347
        if str is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   348
            cls.__str__ = cls.__repr__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   349
        if cmp is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   350
            cls = _add_cmp(cls)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   351
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   352
        if hash is not True and hash is not False and hash is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   353
            raise TypeError(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   354
                "Invalid value for hash.  Must be True, False, or None."
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   355
            )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   356
        elif hash is False or (hash is None and cmp is False):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   357
            pass
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   358
        elif hash is True or (hash is None and cmp is True and frozen is True):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   359
            cls = _add_hash(cls)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   360
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   361
            cls.__hash__ = None
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   362
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   363
        if init is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   364
            cls = _add_init(cls, effectively_frozen)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   365
        if effectively_frozen is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   366
            cls.__setattr__ = _frozen_setattrs
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   367
            cls.__delattr__ = _frozen_delattrs
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   368
            if slots is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   369
                # slots and frozen require __getstate__/__setstate__ to work
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   370
                cls = _add_pickle(cls)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   371
        if slots is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   372
            cls_dict = dict(cls.__dict__)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   373
            cls_dict["__slots__"] = tuple(ca_list)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   374
            for ca_name in ca_list:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   375
                # It might not actually be in there, e.g. if using 'these'.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   376
                cls_dict.pop(ca_name, None)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   377
            cls_dict.pop("__dict__", None)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   378
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   379
            qualname = getattr(cls, "__qualname__", None)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   380
            cls = type(cls)(cls.__name__, cls.__bases__, cls_dict)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   381
            if qualname is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   382
                cls.__qualname__ = qualname
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   383
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   384
        return cls
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   385
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   386
    # attrs_or class type depends on the usage of the decorator.  It's a class
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   387
    # if it's used as `@attributes` but ``None`` if used # as `@attributes()`.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   388
    if maybe_cls is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   389
        return wrap
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   390
    else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   391
        return wrap(maybe_cls)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   392
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   393
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   394
if PY2:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   395
    def _has_frozen_superclass(cls):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   396
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   397
        Check whether *cls* has a frozen ancestor by looking at its
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   398
        __setattr__.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   399
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   400
        return (
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   401
            getattr(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   402
                cls.__setattr__, "__module__", None
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   403
            ) == _frozen_setattrs.__module__ and
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   404
            cls.__setattr__.__name__ == _frozen_setattrs.__name__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   405
        )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   406
else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   407
    def _has_frozen_superclass(cls):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   408
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   409
        Check whether *cls* has a frozen ancestor by looking at its
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   410
        __setattr__.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   411
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   412
        return cls.__setattr__ == _frozen_setattrs
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   413
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   414
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   415
def _attrs_to_tuple(obj, attrs):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   416
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   417
    Create a tuple of all values of *obj*'s *attrs*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   418
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   419
    return tuple(getattr(obj, a.name) for a in attrs)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   420
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   421
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   422
def _add_hash(cls, attrs=None):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   423
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   424
    Add a hash method to *cls*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   425
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   426
    if attrs is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   427
        attrs = [a
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   428
                 for a in cls.__attrs_attrs__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   429
                 if a.hash is True or (a.hash is None and a.cmp is True)]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   430
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   431
    def hash_(self):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   432
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   433
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   434
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   435
        return hash(_attrs_to_tuple(self, attrs))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   436
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   437
    cls.__hash__ = hash_
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   438
    return cls
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   439
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   440
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   441
def _add_cmp(cls, attrs=None):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   442
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   443
    Add comparison methods to *cls*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   444
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   445
    if attrs is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   446
        attrs = [a for a in cls.__attrs_attrs__ if a.cmp]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   447
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   448
    def attrs_to_tuple(obj):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   449
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   450
        Save us some typing.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   451
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   452
        return _attrs_to_tuple(obj, attrs)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   453
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   454
    def eq(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   455
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   456
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   457
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   458
        if other.__class__ is self.__class__:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   459
            return attrs_to_tuple(self) == attrs_to_tuple(other)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   460
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   461
            return NotImplemented
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   462
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   463
    def ne(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   464
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   465
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   466
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   467
        result = eq(self, other)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   468
        if result is NotImplemented:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   469
            return NotImplemented
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   470
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   471
            return not result
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   472
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   473
    def lt(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   474
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   475
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   476
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   477
        if isinstance(other, self.__class__):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   478
            return attrs_to_tuple(self) < attrs_to_tuple(other)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   479
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   480
            return NotImplemented
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   481
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   482
    def le(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   483
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   484
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   485
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   486
        if isinstance(other, self.__class__):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   487
            return attrs_to_tuple(self) <= attrs_to_tuple(other)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   488
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   489
            return NotImplemented
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   490
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   491
    def gt(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   492
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   493
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   494
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   495
        if isinstance(other, self.__class__):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   496
            return attrs_to_tuple(self) > attrs_to_tuple(other)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   497
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   498
            return NotImplemented
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   499
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   500
    def ge(self, other):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   501
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   502
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   503
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   504
        if isinstance(other, self.__class__):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   505
            return attrs_to_tuple(self) >= attrs_to_tuple(other)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   506
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   507
            return NotImplemented
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   508
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   509
    cls.__eq__ = eq
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   510
    cls.__ne__ = ne
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   511
    cls.__lt__ = lt
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   512
    cls.__le__ = le
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   513
    cls.__gt__ = gt
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   514
    cls.__ge__ = ge
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   515
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   516
    return cls
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   517
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   518
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   519
def _add_repr(cls, ns=None, attrs=None):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   520
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   521
    Add a repr method to *cls*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   522
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   523
    if attrs is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   524
        attrs = [a for a in cls.__attrs_attrs__ if a.repr]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   525
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   526
    def repr_(self):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   527
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   528
        Automatically created by attrs.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   529
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   530
        real_cls = self.__class__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   531
        if ns is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   532
            qualname = getattr(real_cls, "__qualname__", None)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   533
            if qualname is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   534
                class_name = qualname.rsplit(">.", 1)[-1]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   535
            else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   536
                class_name = real_cls.__name__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   537
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   538
            class_name = ns + "." + real_cls.__name__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   539
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   540
        return "{0}({1})".format(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   541
            class_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   542
            ", ".join(a.name + "=" + repr(getattr(self, a.name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   543
                      for a in attrs)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   544
        )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   545
    cls.__repr__ = repr_
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   546
    return cls
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   547
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   548
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   549
def _add_init(cls, frozen):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   550
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   551
    Add a __init__ method to *cls*.  If *frozen* is True, make it immutable.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   552
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   553
    attrs = [a for a in cls.__attrs_attrs__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   554
             if a.init or a.default is not NOTHING]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   555
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   556
    # We cache the generated init methods for the same kinds of attributes.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   557
    sha1 = hashlib.sha1()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   558
    sha1.update(repr(attrs).encode("utf-8"))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   559
    unique_filename = "<attrs generated init {0}>".format(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   560
        sha1.hexdigest()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   561
    )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   562
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   563
    script, globs = _attrs_to_script(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   564
        attrs,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   565
        frozen,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   566
        getattr(cls, "__attrs_post_init__", False),
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   567
    )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   568
    locs = {}
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   569
    bytecode = compile(script, unique_filename, "exec")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   570
    attr_dict = dict((a.name, a) for a in attrs)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   571
    globs.update({
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   572
        "NOTHING": NOTHING,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   573
        "attr_dict": attr_dict,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   574
    })
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   575
    if frozen is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   576
        # Save the lookup overhead in __init__ if we need to circumvent
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   577
        # immutability.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   578
        globs["_cached_setattr"] = _obj_setattr
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   579
    eval(bytecode, globs, locs)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   580
    init = locs["__init__"]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   581
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   582
    # In order of debuggers like PDB being able to step through the code,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   583
    # we add a fake linecache entry.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   584
    linecache.cache[unique_filename] = (
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   585
        len(script),
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   586
        None,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   587
        script.splitlines(True),
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   588
        unique_filename
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   589
    )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   590
    cls.__init__ = init
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   591
    return cls
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   592
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   593
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   594
def _add_pickle(cls):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   595
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   596
    Add pickle helpers, needed for frozen and slotted classes
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   597
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   598
    def _slots_getstate__(obj):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   599
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   600
        Play nice with pickle.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   601
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   602
        return tuple(getattr(obj, a.name) for a in fields(obj.__class__))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   603
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   604
    def _slots_setstate__(obj, state):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   605
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   606
        Play nice with pickle.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   607
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   608
        __bound_setattr = _obj_setattr.__get__(obj, Attribute)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   609
        for a, value in zip(fields(obj.__class__), state):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   610
            __bound_setattr(a.name, value)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   611
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   612
    cls.__getstate__ = _slots_getstate__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   613
    cls.__setstate__ = _slots_setstate__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   614
    return cls
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   615
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   616
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   617
def fields(cls):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   618
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   619
    Returns the tuple of ``attrs`` attributes for a class.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   620
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   621
    The tuple also allows accessing the fields by their names (see below for
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   622
    examples).
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   623
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   624
    :param type cls: Class to introspect.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   625
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   626
    :raise TypeError: If *cls* is not a class.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   627
    :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   628
        class.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   629
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   630
    :rtype: tuple (with name accesors) of :class:`attr.Attribute`
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   631
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   632
    ..  versionchanged:: 16.2.0 Returned tuple allows accessing the fields
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   633
        by name.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   634
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   635
    if not isclass(cls):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   636
        raise TypeError("Passed object must be a class.")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   637
    attrs = getattr(cls, "__attrs_attrs__", None)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   638
    if attrs is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   639
        raise NotAnAttrsClassError(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   640
            "{cls!r} is not an attrs-decorated class.".format(cls=cls)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   641
        )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   642
    return attrs
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   643
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   644
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   645
def validate(inst):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   646
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   647
    Validate all attributes on *inst* that have a validator.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   648
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   649
    Leaves all exceptions through.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   650
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   651
    :param inst: Instance of a class with ``attrs`` attributes.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   652
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   653
    if _config._run_validators is False:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   654
        return
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   655
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   656
    for a in fields(inst.__class__):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   657
        v = a.validator
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   658
        if v is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   659
            v(inst, a, getattr(inst, a.name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   660
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   661
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   662
def _attrs_to_script(attrs, frozen, post_init):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   663
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   664
    Return a script of an initializer for *attrs* and a dict of globals.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   665
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   666
    The globals are expected by the generated script.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   667
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   668
     If *frozen* is True, we cannot set the attributes directly so we use
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   669
    a cached ``object.__setattr__``.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   670
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   671
    lines = []
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   672
    if frozen is True:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   673
        lines.append(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   674
            # Circumvent the __setattr__ descriptor to save one lookup per
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   675
            # assignment.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   676
            "_setattr = _cached_setattr.__get__(self, self.__class__)"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   677
        )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   678
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   679
        def fmt_setter(attr_name, value_var):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   680
            return "_setattr('%(attr_name)s', %(value_var)s)" % {
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   681
                "attr_name": attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   682
                "value_var": value_var,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   683
            }
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   684
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   685
        def fmt_setter_with_converter(attr_name, value_var):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   686
            conv_name = _init_convert_pat.format(attr_name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   687
            return "_setattr('%(attr_name)s', %(conv)s(%(value_var)s))" % {
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   688
                "attr_name": attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   689
                "value_var": value_var,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   690
                "conv": conv_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   691
            }
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   692
    else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   693
        def fmt_setter(attr_name, value):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   694
            return "self.%(attr_name)s = %(value)s" % {
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   695
                "attr_name": attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   696
                "value": value,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   697
            }
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   698
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   699
        def fmt_setter_with_converter(attr_name, value_var):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   700
            conv_name = _init_convert_pat.format(attr_name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   701
            return "self.%(attr_name)s = %(conv)s(%(value_var)s)" % {
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   702
                "attr_name": attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   703
                "value_var": value_var,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   704
                "conv": conv_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   705
            }
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   706
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   707
    args = []
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   708
    attrs_to_validate = []
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   709
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   710
    # This is a dictionary of names to validator and converter callables.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   711
    # Injecting this into __init__ globals lets us avoid lookups.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   712
    names_for_globals = {}
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   713
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   714
    for a in attrs:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   715
        if a.validator:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   716
            attrs_to_validate.append(a)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   717
        attr_name = a.name
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   718
        arg_name = a.name.lstrip("_")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   719
        has_factory = isinstance(a.default, Factory)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   720
        if has_factory and a.default.takes_self:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   721
            maybe_self = "self"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   722
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   723
            maybe_self = ""
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   724
        if a.init is False:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   725
            if has_factory:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   726
                init_factory_name = _init_factory_pat.format(a.name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   727
                if a.convert is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   728
                    lines.append(fmt_setter_with_converter(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   729
                        attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   730
                        init_factory_name + "({0})".format(maybe_self)))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   731
                    conv_name = _init_convert_pat.format(a.name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   732
                    names_for_globals[conv_name] = a.convert
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   733
                else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   734
                    lines.append(fmt_setter(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   735
                        attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   736
                        init_factory_name + "({0})".format(maybe_self)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   737
                    ))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   738
                names_for_globals[init_factory_name] = a.default.factory
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   739
            else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   740
                if a.convert is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   741
                    lines.append(fmt_setter_with_converter(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   742
                        attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   743
                        "attr_dict['{attr_name}'].default"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   744
                        .format(attr_name=attr_name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   745
                    ))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   746
                    conv_name = _init_convert_pat.format(a.name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   747
                    names_for_globals[conv_name] = a.convert
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   748
                else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   749
                    lines.append(fmt_setter(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   750
                        attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   751
                        "attr_dict['{attr_name}'].default"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   752
                        .format(attr_name=attr_name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   753
                    ))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   754
        elif a.default is not NOTHING and not has_factory:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   755
            args.append(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   756
                "{arg_name}=attr_dict['{attr_name}'].default".format(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   757
                    arg_name=arg_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   758
                    attr_name=attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   759
                )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   760
            )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   761
            if a.convert is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   762
                lines.append(fmt_setter_with_converter(attr_name, arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   763
                names_for_globals[_init_convert_pat.format(a.name)] = a.convert
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   764
            else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   765
                lines.append(fmt_setter(attr_name, arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   766
        elif has_factory:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   767
            args.append("{arg_name}=NOTHING".format(arg_name=arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   768
            lines.append("if {arg_name} is not NOTHING:"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   769
                         .format(arg_name=arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   770
            init_factory_name = _init_factory_pat.format(a.name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   771
            if a.convert is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   772
                lines.append("    " + fmt_setter_with_converter(attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   773
                                                                arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   774
                lines.append("else:")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   775
                lines.append("    " + fmt_setter_with_converter(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   776
                    attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   777
                    init_factory_name + "({0})".format(maybe_self)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   778
                ))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   779
                names_for_globals[_init_convert_pat.format(a.name)] = a.convert
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   780
            else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   781
                lines.append("    " + fmt_setter(attr_name, arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   782
                lines.append("else:")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   783
                lines.append("    " + fmt_setter(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   784
                    attr_name,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   785
                    init_factory_name + "({0})".format(maybe_self)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   786
                ))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   787
            names_for_globals[init_factory_name] = a.default.factory
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   788
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   789
            args.append(arg_name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   790
            if a.convert is not None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   791
                lines.append(fmt_setter_with_converter(attr_name, arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   792
                names_for_globals[_init_convert_pat.format(a.name)] = a.convert
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   793
            else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   794
                lines.append(fmt_setter(attr_name, arg_name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   795
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   796
    if attrs_to_validate:  # we can skip this if there are no validators.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   797
        names_for_globals["_config"] = _config
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   798
        lines.append("if _config._run_validators is True:")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   799
        for a in attrs_to_validate:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   800
            val_name = "__attr_validator_{}".format(a.name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   801
            attr_name = "__attr_{}".format(a.name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   802
            lines.append("    {}(self, {}, self.{})".format(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   803
                val_name, attr_name, a.name))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   804
            names_for_globals[val_name] = a.validator
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   805
            names_for_globals[attr_name] = a
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   806
    if post_init:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   807
        lines.append("self.__attrs_post_init__()")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   808
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   809
    return """\
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   810
def __init__(self, {args}):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   811
    {lines}
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   812
""".format(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   813
        args=", ".join(args),
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   814
        lines="\n    ".join(lines) if lines else "pass",
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   815
    ), names_for_globals
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   816
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   817
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   818
class Attribute(object):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   819
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   820
    *Read-only* representation of an attribute.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   821
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   822
    :attribute name: The name of the attribute.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   823
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   824
    Plus *all* arguments of :func:`attr.ib`.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   825
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   826
    __slots__ = (
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   827
        "name", "default", "validator", "repr", "cmp", "hash", "init",
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   828
        "convert", "metadata",
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   829
    )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   830
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   831
    def __init__(self, name, default, validator, repr, cmp, hash, init,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   832
                 convert=None, metadata=None):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   833
        # Cache this descriptor here to speed things up later.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   834
        bound_setattr = _obj_setattr.__get__(self, Attribute)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   835
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   836
        bound_setattr("name", name)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   837
        bound_setattr("default", default)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   838
        bound_setattr("validator", validator)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   839
        bound_setattr("repr", repr)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   840
        bound_setattr("cmp", cmp)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   841
        bound_setattr("hash", hash)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   842
        bound_setattr("init", init)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   843
        bound_setattr("convert", convert)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   844
        bound_setattr("metadata", (metadata_proxy(metadata) if metadata
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   845
                                   else _empty_metadata_singleton))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   846
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   847
    def __setattr__(self, name, value):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   848
        raise FrozenInstanceError()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   849
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   850
    @classmethod
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   851
    def from_counting_attr(cls, name, ca):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   852
        inst_dict = {
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   853
            k: getattr(ca, k)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   854
            for k
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   855
            in Attribute.__slots__
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   856
            if k not in (
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   857
                "name", "validator", "default",
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   858
            )  # exclude methods
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   859
        }
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   860
        return cls(name=name, validator=ca._validator, default=ca._default,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   861
                   **inst_dict)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   862
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   863
    # Don't use _add_pickle since fields(Attribute) doesn't work
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   864
    def __getstate__(self):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   865
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   866
        Play nice with pickle.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   867
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   868
        return tuple(getattr(self, name) if name != "metadata"
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   869
                     else dict(self.metadata)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   870
                     for name in self.__slots__)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   871
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   872
    def __setstate__(self, state):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   873
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   874
        Play nice with pickle.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   875
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   876
        bound_setattr = _obj_setattr.__get__(self, Attribute)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   877
        for name, value in zip(self.__slots__, state):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   878
            if name != "metadata":
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   879
                bound_setattr(name, value)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   880
            else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   881
                bound_setattr(name, metadata_proxy(value) if value else
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   882
                              _empty_metadata_singleton)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   883
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   884
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   885
_a = [Attribute(name=name, default=NOTHING, validator=None,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   886
                repr=True, cmp=True, hash=(name != "metadata"), init=True)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   887
      for name in Attribute.__slots__]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   888
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   889
Attribute = _add_hash(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   890
    _add_cmp(_add_repr(Attribute, attrs=_a), attrs=_a),
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   891
    attrs=[a for a in _a if a.hash]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   892
)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   893
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   894
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   895
class _CountingAttr(object):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   896
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   897
    Intermediate representation of attributes that uses a counter to preserve
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   898
    the order in which the attributes have been defined.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   899
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   900
    *Internal* data structure of the attrs library.  Running into is most
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   901
    likely the result of a bug like a forgotten `@attr.s` decorator.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   902
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   903
    __slots__ = ("counter", "_default", "repr", "cmp", "hash", "init",
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   904
                 "metadata", "_validator", "convert")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   905
    __attrs_attrs__ = tuple(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   906
        Attribute(name=name, default=NOTHING, validator=None,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   907
                  repr=True, cmp=True, hash=True, init=True)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   908
        for name
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   909
        in ("counter", "_default", "repr", "cmp", "hash", "init",)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   910
    ) + (
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   911
        Attribute(name="metadata", default=None, validator=None,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   912
                  repr=True, cmp=True, hash=False, init=True),
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   913
    )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   914
    cls_counter = 0
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   915
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   916
    def __init__(self, default, validator, repr, cmp, hash, init, convert,
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   917
                 metadata):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   918
        _CountingAttr.cls_counter += 1
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   919
        self.counter = _CountingAttr.cls_counter
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   920
        self._default = default
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   921
        # If validator is a list/tuple, wrap it using helper validator.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   922
        if validator and isinstance(validator, (list, tuple)):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   923
            self._validator = and_(*validator)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   924
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   925
            self._validator = validator
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   926
        self.repr = repr
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   927
        self.cmp = cmp
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   928
        self.hash = hash
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   929
        self.init = init
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   930
        self.convert = convert
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   931
        self.metadata = metadata
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   932
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   933
    def validator(self, meth):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   934
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   935
        Decorator that adds *meth* to the list of validators.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   936
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   937
        Returns *meth* unchanged.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   938
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   939
        .. versionadded:: 17.1.0
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   940
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   941
        if self._validator is None:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   942
            self._validator = meth
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   943
        else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   944
            self._validator = and_(self._validator, meth)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   945
        return meth
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   946
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   947
    def default(self, meth):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   948
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   949
        Decorator that allows to set the default for an attribute.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   950
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   951
        Returns *meth* unchanged.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   952
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   953
        :raises DefaultAlreadySetError: If default has been set before.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   954
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   955
        .. versionadded:: 17.1.0
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   956
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   957
        if self._default is not NOTHING:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   958
            raise DefaultAlreadySetError()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   959
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   960
        self._default = Factory(meth, takes_self=True)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   961
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   962
        return meth
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   963
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   964
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   965
_CountingAttr = _add_cmp(_add_repr(_CountingAttr))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   966
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   967
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   968
@attributes(slots=True, init=False)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   969
class Factory(object):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   970
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   971
    Stores a factory callable.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   972
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   973
    If passed as the default value to :func:`attr.ib`, the factory is used to
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   974
    generate a new value.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   975
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   976
    :param callable factory: A callable that takes either none or exactly one
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   977
        mandatory positional argument depending on *takes_self*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   978
    :param bool takes_self: Pass the partially initialized instance that is
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   979
        being initialized as a positional argument.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   980
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   981
    .. versionadded:: 17.1.0  *takes_self*
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   982
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   983
    factory = attr()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   984
    takes_self = attr()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   985
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   986
    def __init__(self, factory, takes_self=False):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   987
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   988
        `Factory` is part of the default machinery so if we want a default
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   989
        value here, we have to implement it ourselves.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   990
        """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   991
        self.factory = factory
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   992
        self.takes_self = takes_self
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   993
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   994
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   995
def make_class(name, attrs, bases=(object,), **attributes_arguments):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   996
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   997
    A quick way to create a new class called *name* with *attrs*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   998
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
   999
    :param name: The name for the new class.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1000
    :type name: str
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1001
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1002
    :param attrs: A list of names or a dictionary of mappings of names to
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1003
        attributes.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1004
    :type attrs: :class:`list` or :class:`dict`
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1005
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1006
    :param tuple bases: Classes that the new class will subclass.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1007
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1008
    :param attributes_arguments: Passed unmodified to :func:`attr.s`.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1009
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1010
    :return: A new class with *attrs*.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1011
    :rtype: type
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1012
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1013
    ..  versionadded:: 17.1.0 *bases*
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1014
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1015
    if isinstance(attrs, dict):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1016
        cls_dict = attrs
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1017
    elif isinstance(attrs, (list, tuple)):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1018
        cls_dict = dict((a, attr()) for a in attrs)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1019
    else:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1020
        raise TypeError("attrs argument must be a dict or a list.")
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1021
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1022
    return attributes(**attributes_arguments)(type(name, bases, cls_dict))
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1023
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1024
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1025
# These are required by whithin this module so we define them here and merely
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1026
# import into .validators.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1027
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1028
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1029
@attributes(slots=True, hash=True)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1030
class _AndValidator(object):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1031
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1032
    Compose many validators to a single one.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1033
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1034
    _validators = attr()
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1035
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1036
    def __call__(self, inst, attr, value):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1037
        for v in self._validators:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1038
            v(inst, attr, value)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1039
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1040
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1041
def and_(*validators):
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1042
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1043
    A validator that composes multiple validators into one.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1044
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1045
    When called on a value, it runs all wrapped validators.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1046
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1047
    :param validators: Arbitrary number of validators.
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1048
    :type validators: callables
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1049
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1050
    .. versionadded:: 17.1.0
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1051
    """
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1052
    vals = []
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1053
    for validator in validators:
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1054
        vals.extend(
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1055
            validator._validators if isinstance(validator, _AndValidator)
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1056
            else [validator]
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1057
        )
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1058
765eb17a7eb8 thirdparty: vendor attrs
Siddharth Agarwal <sid0@fb.com>
parents:
diff changeset
  1059
    return _AndValidator(tuple(vals))