Bug 1748737: Bump attrs to be compatible with mochitest r=ahal

A bunch of modern packages (`pytest`, `twisted`, `automat`) all need
`attrs==19.2.0` (or newer).
We _could_ bump `attrs` all the way to the modern `21.4.0` version, but
I'd like to defer that upgrade risk, since there's a
lot of backwards-incompatible changes and deprecations. So, lightly bump
it to `19.2.0`.

As part of bumping it, `pytest` is no longer compatible.
The earliest candidate that seems to be compatible is `pytest` 4.6.6,
which boasts in its release notes that it's resolved some deprecation
warnings against `attrs>=19.2.0`.

Once `pytest` was bumped, it needed a newer version of `pluggy`, which
itself has dependencies.
Since we're using hashes in `tox_requirements.txt`, all dependencies
needed to be hashed as well.

Differential Revision: https://phabricator.services.mozilla.com/D135178
This commit is contained in:
Mitchell Hentges 2022-01-21 18:21:56 +00:00
parent 0116a8d491
commit a37e7812d4
23 changed files with 842 additions and 366 deletions

View file

@ -1,2 +1,2 @@
vendored:third_party/python/glean_parser vendored:third_party/python/glean_parser
pypi:pytest==3.6.2 pypi:pytest==4.6.6

View file

@ -16,9 +16,11 @@ from ._make import (
make_class, make_class,
validate, validate,
) )
from ._version import VersionInfo
__version__ = "19.1.0" __version__ = "19.2.0"
__version_info__ = VersionInfo._from_version_string(__version__)
__title__ = "attrs" __title__ = "attrs"
__description__ = "Classes Without Boilerplate" __description__ = "Classes Without Boilerplate"
@ -37,6 +39,7 @@ s = attributes = attrs
ib = attr = attrib ib = attr = attrib
dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
__all__ = [ __all__ = [
"Attribute", "Attribute",
"Factory", "Factory",

View file

@ -20,12 +20,27 @@ from . import filters as filters
from . import converters as converters from . import converters as converters
from . import validators as validators from . import validators as validators
from ._version import VersionInfo
__version__: str
__version_info__: VersionInfo
__title__: str
__description__: str
__url__: str
__uri__: str
__author__: str
__email__: str
__license__: str
__copyright__: str
_T = TypeVar("_T") _T = TypeVar("_T")
_C = TypeVar("_C", bound=type) _C = TypeVar("_C", bound=type)
_ValidatorType = Callable[[Any, Attribute[_T], _T], Any] _ValidatorType = Callable[[Any, Attribute[_T], _T], Any]
_ConverterType = Callable[[Any], _T] _ConverterType = Callable[[Any], _T]
_FilterType = Callable[[Attribute[_T], _T], bool] _FilterType = Callable[[Attribute[_T], _T], bool]
_ReprType = Callable[[Any], str]
_ReprArgType = Union[bool, _ReprType]
# FIXME: in reality, if multiple validators are passed they must be in a list or tuple, # FIXME: in reality, if multiple validators are passed they must be in a list or tuple,
# but those are invariant and so would prevent subtypes of _ValidatorType from working # but those are invariant and so would prevent subtypes of _ValidatorType from working
# when passed in a list or tuple. # when passed in a list or tuple.
@ -49,18 +64,16 @@ class Attribute(Generic[_T]):
name: str name: str
default: Optional[_T] default: Optional[_T]
validator: Optional[_ValidatorType[_T]] validator: Optional[_ValidatorType[_T]]
repr: bool repr: _ReprArgType
cmp: bool cmp: bool
eq: bool
order: bool
hash: Optional[bool] hash: Optional[bool]
init: bool init: bool
converter: Optional[_ConverterType[_T]] converter: Optional[_ConverterType[_T]]
metadata: Dict[Any, Any] metadata: Dict[Any, Any]
type: Optional[Type[_T]] type: Optional[Type[_T]]
kw_only: bool kw_only: bool
def __lt__(self, x: Attribute[_T]) -> bool: ...
def __le__(self, x: Attribute[_T]) -> bool: ...
def __gt__(self, x: Attribute[_T]) -> bool: ...
def __ge__(self, x: Attribute[_T]) -> bool: ...
# NOTE: We had several choices for the annotation to use for type arg: # NOTE: We had several choices for the annotation to use for type arg:
# 1) Type[_T] # 1) Type[_T]
@ -89,16 +102,17 @@ class Attribute(Generic[_T]):
def attrib( def attrib(
default: None = ..., default: None = ...,
validator: None = ..., validator: None = ...,
repr: bool = ..., repr: _ReprArgType = ...,
cmp: bool = ..., cmp: Optional[bool] = ...,
hash: Optional[bool] = ..., hash: Optional[bool] = ...,
init: bool = ..., init: bool = ...,
convert: None = ...,
metadata: Optional[Mapping[Any, Any]] = ..., metadata: Optional[Mapping[Any, Any]] = ...,
type: None = ..., type: None = ...,
converter: None = ..., converter: None = ...,
factory: None = ..., factory: None = ...,
kw_only: bool = ..., kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Any: ... ) -> Any: ...
# This form catches an explicit None or no default and infers the type from the other arguments. # This form catches an explicit None or no default and infers the type from the other arguments.
@ -106,16 +120,17 @@ def attrib(
def attrib( def attrib(
default: None = ..., default: None = ...,
validator: Optional[_ValidatorArgType[_T]] = ..., validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ..., repr: _ReprArgType = ...,
cmp: bool = ..., cmp: Optional[bool] = ...,
hash: Optional[bool] = ..., hash: Optional[bool] = ...,
init: bool = ..., init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ..., metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ..., type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ..., converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ..., factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ..., kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _T: ... ) -> _T: ...
# This form catches an explicit default argument. # This form catches an explicit default argument.
@ -123,16 +138,17 @@ def attrib(
def attrib( def attrib(
default: _T, default: _T,
validator: Optional[_ValidatorArgType[_T]] = ..., validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ..., repr: _ReprArgType = ...,
cmp: bool = ..., cmp: Optional[bool] = ...,
hash: Optional[bool] = ..., hash: Optional[bool] = ...,
init: bool = ..., init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ..., metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ..., type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ..., converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ..., factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ..., kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _T: ... ) -> _T: ...
# This form covers type=non-Type: e.g. forward references (str), Any # This form covers type=non-Type: e.g. forward references (str), Any
@ -140,16 +156,17 @@ def attrib(
def attrib( def attrib(
default: Optional[_T] = ..., default: Optional[_T] = ...,
validator: Optional[_ValidatorArgType[_T]] = ..., validator: Optional[_ValidatorArgType[_T]] = ...,
repr: bool = ..., repr: _ReprArgType = ...,
cmp: bool = ..., cmp: Optional[bool] = ...,
hash: Optional[bool] = ..., hash: Optional[bool] = ...,
init: bool = ..., init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ..., metadata: Optional[Mapping[Any, Any]] = ...,
type: object = ..., type: object = ...,
converter: Optional[_ConverterType[_T]] = ..., converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ..., factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ..., kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Any: ... ) -> Any: ...
@overload @overload
def attrs( def attrs(
@ -157,7 +174,7 @@ def attrs(
these: Optional[Dict[str, Any]] = ..., these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ..., repr_ns: Optional[str] = ...,
repr: bool = ..., repr: bool = ...,
cmp: bool = ..., cmp: Optional[bool] = ...,
hash: Optional[bool] = ..., hash: Optional[bool] = ...,
init: bool = ..., init: bool = ...,
slots: bool = ..., slots: bool = ...,
@ -168,6 +185,8 @@ def attrs(
kw_only: bool = ..., kw_only: bool = ...,
cache_hash: bool = ..., cache_hash: bool = ...,
auto_exc: bool = ..., auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _C: ... ) -> _C: ...
@overload @overload
def attrs( def attrs(
@ -175,7 +194,7 @@ def attrs(
these: Optional[Dict[str, Any]] = ..., these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ..., repr_ns: Optional[str] = ...,
repr: bool = ..., repr: bool = ...,
cmp: bool = ..., cmp: Optional[bool] = ...,
hash: Optional[bool] = ..., hash: Optional[bool] = ...,
init: bool = ..., init: bool = ...,
slots: bool = ..., slots: bool = ...,
@ -186,6 +205,8 @@ def attrs(
kw_only: bool = ..., kw_only: bool = ...,
cache_hash: bool = ..., cache_hash: bool = ...,
auto_exc: bool = ..., auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Callable[[_C], _C]: ... ) -> Callable[[_C], _C]: ...
# TODO: add support for returning NamedTuple from the mypy plugin # TODO: add support for returning NamedTuple from the mypy plugin
@ -204,7 +225,7 @@ def make_class(
bases: Tuple[type, ...] = ..., bases: Tuple[type, ...] = ...,
repr_ns: Optional[str] = ..., repr_ns: Optional[str] = ...,
repr: bool = ..., repr: bool = ...,
cmp: bool = ..., cmp: Optional[bool] = ...,
hash: Optional[bool] = ..., hash: Optional[bool] = ...,
init: bool = ..., init: bool = ...,
slots: bool = ..., slots: bool = ...,
@ -215,6 +236,8 @@ def make_class(
kw_only: bool = ..., kw_only: bool = ...,
cache_hash: bool = ..., cache_hash: bool = ...,
auto_exc: bool = ..., auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> type: ... ) -> type: ...
# _funcs -- # _funcs --

View file

@ -20,7 +20,7 @@ else:
if PY2: if PY2:
from UserDict import IterableUserDict from UserDict import IterableUserDict
from collections import Mapping, Sequence # noqa from collections import Mapping, Sequence
# We 'bundle' isclass instead of using inspect as importing inspect is # We 'bundle' isclass instead of using inspect as importing inspect is
# fairly expensive (order of 10-15 ms for a modern machine in 2016) # fairly expensive (order of 10-15 ms for a modern machine in 2016)
@ -106,7 +106,8 @@ else: # Python 3 and later.
consequences of not setting the cell on Python 2. consequences of not setting the cell on Python 2.
""" """
warnings.warn( warnings.warn(
"Missing ctypes. Some features like bare super() or accessing " "Running interpreter doesn't sufficiently support code object "
"introspection. Some features like bare super() or accessing "
"__class__ will not work with slotted classes.", "__class__ will not work with slotted classes.",
RuntimeWarning, RuntimeWarning,
stacklevel=2, stacklevel=2,
@ -124,36 +125,106 @@ else: # Python 3 and later.
return types.MappingProxyType(dict(d)) return types.MappingProxyType(dict(d))
def import_ctypes():
"""
Moved into a function for testability.
"""
import ctypes
return ctypes
def make_set_closure_cell(): def make_set_closure_cell():
"""Return a function of two arguments (cell, value) which sets
the value stored in the closure cell `cell` to `value`.
""" """
Moved into a function for testability. # pypy makes this easy. (It also supports the logic below, but
""" # why not do the easy/fast thing?)
if PYPY: # pragma: no cover if PYPY: # pragma: no cover
def set_closure_cell(cell, value): def set_closure_cell(cell, value):
cell.__setstate__((value,)) cell.__setstate__((value,))
else: return set_closure_cell
try:
ctypes = import_ctypes()
set_closure_cell = ctypes.pythonapi.PyCell_Set # Otherwise gotta do it the hard way.
set_closure_cell.argtypes = (ctypes.py_object, ctypes.py_object)
set_closure_cell.restype = ctypes.c_int # Create a function that will set its first cellvar to `value`.
except Exception: def set_first_cellvar_to(value):
# We try best effort to set the cell, but sometimes it's not x = value
# possible. For example on Jython or on GAE. return
set_closure_cell = just_warn
return set_closure_cell # This function will be eliminated as dead code, but
# not before its reference to `x` forces `x` to be
# represented as a closure cell rather than a local.
def force_x_to_be_a_cell(): # pragma: no cover
return x
try:
# Extract the code object and make sure our assumptions about
# the closure behavior are correct.
if PY2:
co = set_first_cellvar_to.func_code
else:
co = set_first_cellvar_to.__code__
if co.co_cellvars != ("x",) or co.co_freevars != ():
raise AssertionError # pragma: no cover
# Convert this code object to a code object that sets the
# function's first _freevar_ (not cellvar) to the argument.
if sys.version_info >= (3, 8):
# CPython 3.8+ has an incompatible CodeType signature
# (added a posonlyargcount argument) but also added
# CodeType.replace() to do this without counting parameters.
set_first_freevar_code = co.replace(
co_cellvars=co.co_freevars, co_freevars=co.co_cellvars
)
else:
args = [co.co_argcount]
if not PY2:
args.append(co.co_kwonlyargcount)
args.extend(
[
co.co_nlocals,
co.co_stacksize,
co.co_flags,
co.co_code,
co.co_consts,
co.co_names,
co.co_varnames,
co.co_filename,
co.co_name,
co.co_firstlineno,
co.co_lnotab,
# These two arguments are reversed:
co.co_cellvars,
co.co_freevars,
]
)
set_first_freevar_code = types.CodeType(*args)
def set_closure_cell(cell, value):
# Create a function using the set_first_freevar_code,
# whose first closure cell is `cell`. Calling it will
# change the value of that cell.
setter = types.FunctionType(
set_first_freevar_code, {}, "setter", (), (cell,)
)
# And call it to set the cell.
setter(value)
# Make sure it works on this interpreter:
def make_func_with_cell():
x = None
def func():
return x # pragma: no cover
return func
if PY2:
cell = make_func_with_cell().func_closure[0]
else:
cell = make_func_with_cell().__closure__[0]
set_closure_cell(cell, 100)
if cell.cell_contents != 100:
raise AssertionError # pragma: no cover
except Exception:
return just_warn
else:
return set_closure_cell
set_closure_cell = make_set_closure_cell() set_closure_cell = make_set_closure_cell()

View file

@ -24,7 +24,7 @@ def asdict(
``attrs``-decorated. ``attrs``-decorated.
:param callable filter: A callable whose return code determines whether an :param callable filter: A callable whose return code determines whether an
attribute or element is included (``True``) or dropped (``False``). Is attribute or element is included (``True``) or dropped (``False``). Is
called with the :class:`attr.Attribute` as the first argument and the called with the `attr.Attribute` as the first argument and the
value as the second argument. value as the second argument.
:param callable dict_factory: A callable to produce dictionaries from. For :param callable dict_factory: A callable to produce dictionaries from. For
example, to produce ordered dictionaries instead of normal Python example, to produce ordered dictionaries instead of normal Python
@ -130,7 +130,7 @@ def astuple(
``attrs``-decorated. ``attrs``-decorated.
:param callable filter: A callable whose return code determines whether an :param callable filter: A callable whose return code determines whether an
attribute or element is included (``True``) or dropped (``False``). Is attribute or element is included (``True``) or dropped (``False``). Is
called with the :class:`attr.Attribute` as the first argument and the called with the `attr.Attribute` as the first argument and the
value as the second argument. value as the second argument.
:param callable tuple_factory: A callable to produce tuples from. For :param callable tuple_factory: A callable to produce tuples from. For
example, to produce lists instead of tuples. example, to produce lists instead of tuples.
@ -219,7 +219,7 @@ def has(cls):
:param type cls: Class to introspect. :param type cls: Class to introspect.
:raise TypeError: If *cls* is not a class. :raise TypeError: If *cls* is not a class.
:rtype: :class:`bool` :rtype: bool
""" """
return getattr(cls, "__attrs_attrs__", None) is not None return getattr(cls, "__attrs_attrs__", None) is not None
@ -239,7 +239,7 @@ def assoc(inst, **changes):
class. class.
.. deprecated:: 17.1.0 .. deprecated:: 17.1.0
Use :func:`evolve` instead. Use `evolve` instead.
""" """
import warnings import warnings

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,85 @@
from __future__ import absolute_import, division, print_function
from functools import total_ordering
from ._funcs import astuple
from ._make import attrib, attrs
@total_ordering
@attrs(eq=False, order=False, slots=True, frozen=True)
class VersionInfo(object):
"""
A version object that can be compared to tuple of length 1--4:
>>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2)
True
>>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1)
True
>>> vi = attr.VersionInfo(19, 2, 0, "final")
>>> vi < (19, 1, 1)
False
>>> vi < (19,)
False
>>> vi == (19, 2,)
True
>>> vi == (19, 2, 1)
False
.. versionadded:: 19.2
"""
year = attrib(type=int)
minor = attrib(type=int)
micro = attrib(type=int)
releaselevel = attrib(type=str)
@classmethod
def _from_version_string(cls, s):
"""
Parse *s* and return a _VersionInfo.
"""
v = s.split(".")
if len(v) == 3:
v.append("final")
return cls(
year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3]
)
def _ensure_tuple(self, other):
"""
Ensure *other* is a tuple of a valid length.
Returns a possibly transformed *other* and ourselves as a tuple of
the same length as *other*.
"""
if self.__class__ is other.__class__:
other = astuple(other)
if not isinstance(other, tuple):
raise NotImplementedError
if not (1 <= len(other) <= 4):
raise NotImplementedError
return astuple(self)[: len(other)], other
def __eq__(self, other):
try:
us, them = self._ensure_tuple(other)
except NotImplementedError:
return NotImplemented
return us == them
def __lt__(self, other):
try:
us, them = self._ensure_tuple(other)
except NotImplementedError:
return NotImplemented
# Since alphabetically "dev0" < "final" < "post1" < "post2", we don't
# have to do anything special with releaselevel for now.
return us < them

View file

@ -0,0 +1,9 @@
class VersionInfo:
@property
def year(self) -> int: ...
@property
def minor(self) -> int: ...
@property
def micro(self) -> int: ...
@property
def releaselevel(self) -> str: ...

View file

@ -32,14 +32,14 @@ def default_if_none(default=NOTHING, factory=None):
result of *factory*. result of *factory*.
:param default: Value to be used if ``None`` is passed. Passing an instance :param default: Value to be used if ``None`` is passed. Passing an instance
of :class:`attr.Factory` is supported, however the ``takes_self`` option of `attr.Factory` is supported, however the ``takes_self`` option
is *not*. is *not*.
:param callable factory: A callable that takes not parameters whose result :param callable factory: A callable that takes not parameters whose result
is used if ``None`` is passed. is used if ``None`` is passed.
:raises TypeError: If **neither** *default* or *factory* is passed. :raises TypeError: If **neither** *default* or *factory* is passed.
:raises TypeError: If **both** *default* and *factory* are passed. :raises TypeError: If **both** *default* and *factory* are passed.
:raises ValueError: If an instance of :class:`attr.Factory` is passed with :raises ValueError: If an instance of `attr.Factory` is passed with
``takes_self=True``. ``takes_self=True``.
.. versionadded:: 18.2.0 .. versionadded:: 18.2.0

View file

@ -6,7 +6,7 @@ class FrozenInstanceError(AttributeError):
A frozen/immutable instance has been attempted to be modified. A frozen/immutable instance has been attempted to be modified.
It mirrors the behavior of ``namedtuples`` by using the same error message It mirrors the behavior of ``namedtuples`` by using the same error message
and subclassing :exc:`AttributeError`. and subclassing `AttributeError`.
.. versionadded:: 16.1.0 .. versionadded:: 16.1.0
""" """
@ -55,3 +55,20 @@ class PythonTooOldError(RuntimeError):
.. versionadded:: 18.2.0 .. versionadded:: 18.2.0
""" """
class NotCallableError(TypeError):
"""
A ``attr.ib()`` requiring a callable has been set with a value
that is not callable.
.. versionadded:: 19.2.0
"""
def __init__(self, msg, value):
super(TypeError, self).__init__(msg, value)
self.msg = msg
self.value = value
def __str__(self):
return str(self.msg)

View file

@ -1,3 +1,5 @@
from typing import Any
class FrozenInstanceError(AttributeError): class FrozenInstanceError(AttributeError):
msg: str = ... msg: str = ...
@ -5,3 +7,9 @@ class AttrsAttributeNotFoundError(ValueError): ...
class NotAnAttrsClassError(ValueError): ... class NotAnAttrsClassError(ValueError): ...
class DefaultAlreadySetError(RuntimeError): ... class DefaultAlreadySetError(RuntimeError): ...
class UnannotatedAttributeError(RuntimeError): ... class UnannotatedAttributeError(RuntimeError): ...
class PythonTooOldError(RuntimeError): ...
class NotCallableError(TypeError):
msg: str = ...
value: Any = ...
def __init__(self, msg: str, value: Any) -> None: ...

View file

@ -1,5 +1,5 @@
""" """
Commonly useful filters for :func:`attr.asdict`. Commonly useful filters for `attr.asdict`.
""" """
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
@ -23,9 +23,9 @@ def include(*what):
Whitelist *what*. Whitelist *what*.
:param what: What to whitelist. :param what: What to whitelist.
:type what: :class:`list` of :class:`type` or :class:`attr.Attribute`\\ s :type what: `list` of `type` or `attr.Attribute`\\ s
:rtype: :class:`callable` :rtype: `callable`
""" """
cls, attrs = _split_what(what) cls, attrs = _split_what(what)
@ -40,9 +40,9 @@ def exclude(*what):
Blacklist *what*. Blacklist *what*.
:param what: What to blacklist. :param what: What to blacklist.
:type what: :class:`list` of classes or :class:`attr.Attribute`\\ s. :type what: `list` of classes or `attr.Attribute`\\ s.
:rtype: :class:`callable` :rtype: `callable`
""" """
cls, attrs = _split_what(what) cls, attrs = _split_what(what)

View file

@ -4,10 +4,23 @@ Commonly useful validators.
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import re
from ._make import _AndValidator, and_, attrib, attrs from ._make import _AndValidator, and_, attrib, attrs
from .exceptions import NotCallableError
__all__ = ["and_", "in_", "instance_of", "optional", "provides"] __all__ = [
"and_",
"deep_iterable",
"deep_mapping",
"in_",
"instance_of",
"is_callable",
"matches_re",
"optional",
"provides",
]
@attrs(repr=False, slots=True, hash=True) @attrs(repr=False, slots=True, hash=True)
@ -40,20 +53,92 @@ class _InstanceOfValidator(object):
def instance_of(type): def instance_of(type):
""" """
A validator that raises a :exc:`TypeError` if the initializer is called A validator that raises a `TypeError` if the initializer is called
with a wrong type for this particular attribute (checks are performed using with a wrong type for this particular attribute (checks are performed using
:func:`isinstance` therefore it's also valid to pass a tuple of types). `isinstance` therefore it's also valid to pass a tuple of types).
:param type: The type to check for. :param type: The type to check for.
:type type: type or tuple of types :type type: type or tuple of types
:raises TypeError: With a human readable error message, the attribute :raises TypeError: With a human readable error message, the attribute
(of type :class:`attr.Attribute`), the expected type, and the value it (of type `attr.Attribute`), the expected type, and the value it
got. got.
""" """
return _InstanceOfValidator(type) return _InstanceOfValidator(type)
@attrs(repr=False, frozen=True)
class _MatchesReValidator(object):
regex = attrib()
flags = attrib()
match_func = attrib()
def __call__(self, inst, attr, value):
"""
We use a callable class to be able to change the ``__repr__``.
"""
if not self.match_func(value):
raise ValueError(
"'{name}' must match regex {regex!r}"
" ({value!r} doesn't)".format(
name=attr.name, regex=self.regex.pattern, value=value
),
attr,
self.regex,
value,
)
def __repr__(self):
return "<matches_re validator for pattern {regex!r}>".format(
regex=self.regex
)
def matches_re(regex, flags=0, func=None):
r"""
A validator that raises `ValueError` if the initializer is called
with a string that doesn't match *regex*.
:param str regex: a regex string to match against
:param int flags: flags that will be passed to the underlying re function
(default 0)
:param callable func: which underlying `re` function to call (options
are `re.fullmatch`, `re.search`, `re.match`, default
is ``None`` which means either `re.fullmatch` or an emulation of
it on Python 2). For performance reasons, they won't be used directly
but on a pre-`re.compile`\ ed pattern.
.. versionadded:: 19.2.0
"""
fullmatch = getattr(re, "fullmatch", None)
valid_funcs = (fullmatch, None, re.search, re.match)
if func not in valid_funcs:
raise ValueError(
"'func' must be one of %s."
% (
", ".join(
sorted(
e and e.__name__ or "None" for e in set(valid_funcs)
)
),
)
)
pattern = re.compile(regex, flags)
if func is re.match:
match_func = pattern.match
elif func is re.search:
match_func = pattern.search
else:
if fullmatch:
match_func = pattern.fullmatch
else:
pattern = re.compile(r"(?:{})\Z".format(regex), flags)
match_func = pattern.match
return _MatchesReValidator(pattern, flags, match_func)
@attrs(repr=False, slots=True, hash=True) @attrs(repr=False, slots=True, hash=True)
class _ProvidesValidator(object): class _ProvidesValidator(object):
interface = attrib() interface = attrib()
@ -81,7 +166,7 @@ class _ProvidesValidator(object):
def provides(interface): def provides(interface):
""" """
A validator that raises a :exc:`TypeError` if the initializer is called A validator that raises a `TypeError` if the initializer is called
with an object that does not provide the requested *interface* (checks are with an object that does not provide the requested *interface* (checks are
performed using ``interface.providedBy(value)`` (see `zope.interface performed using ``interface.providedBy(value)`` (see `zope.interface
<https://zopeinterface.readthedocs.io/en/latest/>`_). <https://zopeinterface.readthedocs.io/en/latest/>`_).
@ -89,7 +174,7 @@ def provides(interface):
:param zope.interface.Interface interface: The interface to check for. :param zope.interface.Interface interface: The interface to check for.
:raises TypeError: With a human readable error message, the attribute :raises TypeError: With a human readable error message, the attribute
(of type :class:`attr.Attribute`), the expected interface, and the (of type `attr.Attribute`), the expected interface, and the
value it got. value it got.
""" """
return _ProvidesValidator(interface) return _ProvidesValidator(interface)
@ -119,7 +204,7 @@ def optional(validator):
:param validator: A validator (or a list of validators) that is used for :param validator: A validator (or a list of validators) that is used for
non-``None`` values. non-``None`` values.
:type validator: callable or :class:`list` of callables. :type validator: callable or `list` of callables.
.. versionadded:: 15.1.0 .. versionadded:: 15.1.0
.. versionchanged:: 17.1.0 *validator* can be a list of validators. .. versionchanged:: 17.1.0 *validator* can be a list of validators.
@ -154,15 +239,15 @@ class _InValidator(object):
def in_(options): def in_(options):
""" """
A validator that raises a :exc:`ValueError` if the initializer is called A validator that raises a `ValueError` if the initializer is called
with a value that does not belong in the options provided. The check is with a value that does not belong in the options provided. The check is
performed using ``value in options``. performed using ``value in options``.
:param options: Allowed options. :param options: Allowed options.
:type options: list, tuple, :class:`enum.Enum`, ... :type options: list, tuple, `enum.Enum`, ...
:raises ValueError: With a human readable error message, the attribute (of :raises ValueError: With a human readable error message, the attribute (of
type :class:`attr.Attribute`), the expected options, and the value it type `attr.Attribute`), the expected options, and the value it
got. got.
.. versionadded:: 17.1.0 .. versionadded:: 17.1.0
@ -177,7 +262,16 @@ class _IsCallableValidator(object):
We use a callable class to be able to change the ``__repr__``. We use a callable class to be able to change the ``__repr__``.
""" """
if not callable(value): if not callable(value):
raise TypeError("'{name}' must be callable".format(name=attr.name)) message = (
"'{name}' must be callable "
"(got {value!r} that is a {actual!r})."
)
raise NotCallableError(
msg=message.format(
name=attr.name, value=value, actual=value.__class__
),
value=value,
)
def __repr__(self): def __repr__(self):
return "<is_callable validator>" return "<is_callable validator>"
@ -185,13 +279,15 @@ class _IsCallableValidator(object):
def is_callable(): def is_callable():
""" """
A validator that raises a :class:`TypeError` if the initializer is called A validator that raises a `attr.exceptions.NotCallableError` if the
with a value for this particular attribute that is not callable. initializer is called with a value for this particular attribute
that is not callable.
.. versionadded:: 19.1.0 .. versionadded:: 19.1.0
:raises TypeError: With a human readable error message containing the :raises `attr.exceptions.NotCallableError`: With a human readable error
attribute (of type :class:`attr.Attribute`) name. message containing the attribute (`attr.Attribute`) name,
and the value it got.
""" """
return _IsCallableValidator() return _IsCallableValidator()

View file

@ -1,24 +1,66 @@
from typing import Container, List, Union, TypeVar, Type, Any, Optional, Tuple from typing import (
Container,
List,
Union,
TypeVar,
Type,
Any,
Optional,
Tuple,
Iterable,
Mapping,
Callable,
Match,
AnyStr,
overload,
)
from . import _ValidatorType from . import _ValidatorType
_T = TypeVar("_T") _T = TypeVar("_T")
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
_T3 = TypeVar("_T3")
_I = TypeVar("_I", bound=Iterable)
_K = TypeVar("_K")
_V = TypeVar("_V")
_M = TypeVar("_M", bound=Mapping)
# To be more precise on instance_of use some overloads.
# If there are more than 3 items in the tuple then we fall back to Any
@overload
def instance_of(type: Type[_T]) -> _ValidatorType[_T]: ...
@overload
def instance_of(type: Tuple[Type[_T]]) -> _ValidatorType[_T]: ...
@overload
def instance_of( def instance_of(
type: Union[Tuple[Type[_T], ...], Type[_T]] type: Tuple[Type[_T1], Type[_T2]]
) -> _ValidatorType[_T]: ... ) -> _ValidatorType[Union[_T1, _T2]]: ...
@overload
def instance_of(
type: Tuple[Type[_T1], Type[_T2], Type[_T3]]
) -> _ValidatorType[Union[_T1, _T2, _T3]]: ...
@overload
def instance_of(type: Tuple[type, ...]) -> _ValidatorType[Any]: ...
def provides(interface: Any) -> _ValidatorType[Any]: ... def provides(interface: Any) -> _ValidatorType[Any]: ...
def optional( def optional(
validator: Union[_ValidatorType[_T], List[_ValidatorType[_T]]] validator: Union[_ValidatorType[_T], List[_ValidatorType[_T]]]
) -> _ValidatorType[Optional[_T]]: ... ) -> _ValidatorType[Optional[_T]]: ...
def in_(options: Container[_T]) -> _ValidatorType[_T]: ... def in_(options: Container[_T]) -> _ValidatorType[_T]: ...
def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ...
def matches_re(
regex: AnyStr,
flags: int = ...,
func: Optional[
Callable[[AnyStr, AnyStr, int], Optional[Match[AnyStr]]]
] = ...,
) -> _ValidatorType[AnyStr]: ...
def deep_iterable( def deep_iterable(
member_validator: _ValidatorType[_T], member_validator: _ValidatorType[_T],
iterable_validator: Optional[_ValidatorType[_T]], iterable_validator: Optional[_ValidatorType[_I]] = ...,
) -> _ValidatorType[_T]: ... ) -> _ValidatorType[_I]: ...
def deep_mapping( def deep_mapping(
key_validator: _ValidatorType[_T], key_validator: _ValidatorType[_K],
value_validator: _ValidatorType[_T], value_validator: _ValidatorType[_V],
mapping_validator: Optional[_ValidatorType[_T]], mapping_validator: Optional[_ValidatorType[_M]] = ...,
) -> _ValidatorType[_T]: ... ) -> _ValidatorType[_M]: ...
def is_callable() -> _ValidatorType[_T]: ... def is_callable() -> _ValidatorType[_T]: ...

View file

@ -1,20 +0,0 @@
attr/__init__.py,sha256=3XomfUfit8bVVEmSf1bRhLnRMPKauPbzFqPUnVRPgXw,1244
attr/__init__.pyi,sha256=OON4rNWdgL69frd_WdrxtuQe8CEczl3aFpgifFeESN8,7769
attr/_compat.py,sha256=GcjqWHrwUWGVCbDKY7twYt-Rr_4nPJqBnfrf5SeHsIY,4583
attr/_config.py,sha256=_KvW0mQdH2PYjHc0YfIUaV_o2pVfM7ziMEYTxwmEhOA,514
attr/_funcs.py,sha256=7v3MNMHdOUP2NkiLPwEiWAorBs3uNQq5Rn70Odr5uqo,9725
attr/_make.py,sha256=be1PmzR8EDGfVA2Cx6ljsTIuXRxW2tEWPpTqtQXde0Y,68317
attr/converters.py,sha256=SFPiz6-hAs2pw3kn7SzkBcdpE9AjW8iT9wjpe2eLDrQ,2155
attr/converters.pyi,sha256=wAhCoOT1MFV8t323rpD87O7bxQ8CYLTPiBQd-29BieI,351
attr/exceptions.py,sha256=N0WQfKvBVd4GWgDxTbFScg4ajy7-HlyvXiwlSQBA0jA,1272
attr/exceptions.pyi,sha256=sq7TbBEGGSf81uFXScW9_aO62vd0v6LAvqz0a8Hrsxw,257
attr/filters.py,sha256=s6NrcRWJKlCQauPEH0S4lmgFwlCdUQcHKcNkDHpptN4,1153
attr/filters.pyi,sha256=xDpmKQlFdssgxGa5tsl1ADh_3zwAwAT4vUhd8h-8-Tk,214
attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
attr/validators.py,sha256=ZAf_y5wNHyq2Rdlin_fwplQnU2u5wZnvmYJq1JddPtM,8750
attr/validators.pyi,sha256=p2xr2ob8RaKW3PqlKDrQQVAyl8ZH4pNdlZzWXapGPjk,897
attrs-19.1.0.dist-info/LICENSE,sha256=v2WaKLSSQGAvVrvfSQy-LsUJsVuY-Z17GaUsdA4yeGM,1082
attrs-19.1.0.dist-info/METADATA,sha256=5yXp3BTFGRkY2hQDs18h-2dT7xnSlExRUfxvujCtHTE,10275
attrs-19.1.0.dist-info/WHEEL,sha256=_wJFdOYk7i3xxT8ElOkUJvOdOvfNGbR9g-bf6UQT6sU,110
attrs-19.1.0.dist-info/top_level.txt,sha256=tlRYMddkRlKPqJ96wP2_j9uEsmcNHgD2SbuWd4CzGVU,5
attrs-19.1.0.dist-info/RECORD,,

View file

@ -1,6 +1,6 @@
Metadata-Version: 2.1 Metadata-Version: 2.1
Name: attrs Name: attrs
Version: 19.1.0 Version: 19.2.0
Summary: Classes Without Boilerplate Summary: Classes Without Boilerplate
Home-page: https://www.attrs.org/ Home-page: https://www.attrs.org/
Author: Hynek Schlawack Author: Hynek Schlawack
@ -30,11 +30,20 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Description-Content-Type: text/x-rst
Provides-Extra: azure-pipelines
Requires-Dist: coverage ; extra == 'azure-pipelines'
Requires-Dist: hypothesis ; extra == 'azure-pipelines'
Requires-Dist: pympler ; extra == 'azure-pipelines'
Requires-Dist: pytest (>=4.3.0) ; extra == 'azure-pipelines'
Requires-Dist: six ; extra == 'azure-pipelines'
Requires-Dist: zope.interface ; extra == 'azure-pipelines'
Requires-Dist: pytest-azurepipelines ; extra == 'azure-pipelines'
Provides-Extra: dev Provides-Extra: dev
Requires-Dist: coverage ; extra == 'dev' Requires-Dist: coverage ; extra == 'dev'
Requires-Dist: hypothesis ; extra == 'dev' Requires-Dist: hypothesis ; extra == 'dev'
Requires-Dist: pympler ; extra == 'dev' Requires-Dist: pympler ; extra == 'dev'
Requires-Dist: pytest ; extra == 'dev' Requires-Dist: pytest (>=4.3.0) ; extra == 'dev'
Requires-Dist: six ; extra == 'dev' Requires-Dist: six ; extra == 'dev'
Requires-Dist: zope.interface ; extra == 'dev' Requires-Dist: zope.interface ; extra == 'dev'
Requires-Dist: sphinx ; extra == 'dev' Requires-Dist: sphinx ; extra == 'dev'
@ -46,7 +55,7 @@ Provides-Extra: tests
Requires-Dist: coverage ; extra == 'tests' Requires-Dist: coverage ; extra == 'tests'
Requires-Dist: hypothesis ; extra == 'tests' Requires-Dist: hypothesis ; extra == 'tests'
Requires-Dist: pympler ; extra == 'tests' Requires-Dist: pympler ; extra == 'tests'
Requires-Dist: pytest ; extra == 'tests' Requires-Dist: pytest (>=4.3.0) ; extra == 'tests'
Requires-Dist: six ; extra == 'tests' Requires-Dist: six ; extra == 'tests'
Requires-Dist: zope.interface ; extra == 'tests' Requires-Dist: zope.interface ; extra == 'tests'
@ -61,8 +70,8 @@ Requires-Dist: zope.interface ; extra == 'tests'
:target: https://www.attrs.org/en/stable/?badge=stable :target: https://www.attrs.org/en/stable/?badge=stable
:alt: Documentation Status :alt: Documentation Status
.. image:: https://travis-ci.org/python-attrs/attrs.svg?branch=master .. image:: https://attrs.visualstudio.com/attrs/_apis/build/status/python-attrs.attrs?branchName=master
:target: https://travis-ci.org/python-attrs/attrs :target: https://attrs.visualstudio.com/attrs/_build/latest?definitionId=1&branchName=master
:alt: CI Status :alt: CI Status
.. image:: https://codecov.io/github/python-attrs/attrs/branch/master/graph/badge.svg .. image:: https://codecov.io/github/python-attrs/attrs/branch/master/graph/badge.svg
@ -70,7 +79,7 @@ Requires-Dist: zope.interface ; extra == 'tests'
:alt: Test Coverage :alt: Test Coverage
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg .. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black :target: https://github.com/psf/black
:alt: Code style: black :alt: Code style: black
.. teaser-begin .. teaser-begin
@ -124,7 +133,7 @@ After *declaring* your attributes ``attrs`` gives you:
- a concise and explicit overview of the class's attributes, - a concise and explicit overview of the class's attributes,
- a nice human-readable ``__repr__``, - a nice human-readable ``__repr__``,
- a complete set of comparison methods, - a complete set of comparison methods (equality and ordering),
- an initializer, - an initializer,
- and much more, - and much more,
@ -153,12 +162,12 @@ Testimonials
It exerts a subtle, but positive, design influence in all the codebases Ive see it used in. It exerts a subtle, but positive, design influence in all the codebases Ive see it used in.
**Kenneth Reitz**, author of `Requests <http://www.python-requests.org/>`_ and Developer Advocate at DigitalOcean, (`on paper no less <https://twitter.com/hynek/status/866817877650751488>`_!): **Kenneth Reitz**, creator of `Requests <https://github.com/psf/requests>`_ (`on paper no less <https://twitter.com/hynek/status/866817877650751488>`_!):
attrs—classes for humans. I like it. attrs—classes for humans. I like it.
**Łukasz Langa**, prolific CPython core developer and Production Engineer at Facebook: **Łukasz Langa**, creator of `Black <https://github.com/psf/black>`_, prolific Python core developer, and release manager for Python 3.8 and 3.9:
I'm increasingly digging your attr.ocity. Good job! I'm increasingly digging your attr.ocity. Good job!
@ -193,44 +202,70 @@ If you'd like to contribute to ``attrs`` you're most welcome and we've written `
Release Information Release Information
=================== ===================
19.1.0 (2019-03-03) 19.2.0 (2019-10-01)
------------------- -------------------
Backward-incompatible Changes Backward-incompatible Changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed a bug where deserialized objects with ``cache_hash=True`` could have incorrect hash code values. - Removed deprecated ``Attribute`` attribute ``convert`` per scheduled removal on 2019/1.
This change breaks classes with ``cache_hash=True`` when a custom ``__setstate__`` is present. This planned deprecation is tracked in issue `#307 <https://github.com/python-attrs/attrs/issues/307>`_.
An exception will be thrown when applying the ``attrs`` annotation to such a class. `#504 <https://github.com/python-attrs/attrs/issues/504>`_
This limitation is tracked in issue `#494 <https://github.com/python-attrs/attrs/issues/494>`_. - ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` do not consider subclasses comparable anymore.
`#482 <https://github.com/python-attrs/attrs/issues/482>`_
This has been deprecated since 18.2.0 and was raising a ``DeprecationWarning`` for over a year.
`#570 <https://github.com/python-attrs/attrs/issues/570>`_
Deprecations
^^^^^^^^^^^^
- The ``cmp`` argument to ``attr.s()`` and ``attr.ib()`` is now deprecated.
Please use ``eq`` to add equality methods (``__eq__`` and ``__ne__``) and ``order`` to add ordering methods (``__lt__``, ``__le__``, ``__gt__``, and ``__ge__``) instead just like with `dataclasses <https://docs.python.org/3/library/dataclasses.html>`_.
Both are effectively ``True`` by default but it's enough to set ``eq=False`` to disable both at once.
Passing ``eq=False, order=True`` explicitly will raise a ``ValueError`` though.
Since this is arguably a deeper backward-compatibility break, it will have an extended deprecation period until 2021-06-01.
After that day, the ``cmp`` argument will be removed.
``attr.Attribute`` also isn't orderable anymore.
`#574 <https://github.com/python-attrs/attrs/issues/574>`_
Changes Changes
^^^^^^^ ^^^^^^^
- Add ``is_callable``, ``deep_iterable``, and ``deep_mapping`` validators. - Updated ``attr.validators.__all__`` to include new validators added in `#425`_.
`#517 <https://github.com/python-attrs/attrs/issues/517>`_
- Slotted classes now use a pure Python mechanism to rewrite the ``__class__`` cell when rebuilding the class, so ``super()`` works even on environments where ``ctypes`` is not installed.
`#522 <https://github.com/python-attrs/attrs/issues/522>`_
- When collecting attributes using ``@attr.s(auto_attribs=True)``, attributes with a default of ``None`` are now deleted too.
`#523 <https://github.com/python-attrs/attrs/issues/523>`_,
`#556 <https://github.com/python-attrs/attrs/issues/556>`_
- Fixed ``attr.validators.deep_iterable()`` and ``attr.validators.deep_mapping()`` type stubs.
`#533 <https://github.com/python-attrs/attrs/issues/533>`_
- ``attr.validators.is_callable()`` validator now raises an exception ``attr.exceptions.NotCallableError``, a subclass of ``TypeError``, informing the received value.
`#536 <https://github.com/python-attrs/attrs/issues/536>`_
- ``@attr.s(auto_exc=True)`` now generates classes that are hashable by ID, as the documentation always claimed it would.
`#543 <https://github.com/python-attrs/attrs/issues/543>`_,
`#563 <https://github.com/python-attrs/attrs/issues/563>`_
- Added ``attr.validators.matches_re()`` that checks string attributes whether they match a regular expression.
`#552 <https://github.com/python-attrs/attrs/issues/552>`_
- Keyword-only attributes (``kw_only=True``) and attributes that are excluded from the ``attrs``'s ``__init__`` (``init=False``) now can appear before mandatory attributes.
`#559 <https://github.com/python-attrs/attrs/issues/559>`_
- The fake filename for generated methods is now more stable.
It won't change when you restart the process.
`#560 <https://github.com/python-attrs/attrs/issues/560>`_
- The value passed to ``@attr.ib(repr=…)`` can now be either a boolean (as before) or a callable.
That callable must return a string and is then used for formatting the attribute by the generated ``__repr__()`` method.
`#568 <https://github.com/python-attrs/attrs/issues/568>`_
- Added ``attr.__version_info__`` that can be used to reliably check the version of ``attrs`` and write forward- and backward-compatible code.
Please check out the `section on deprecated APIs <http://www.attrs.org/en/stable/api.html#deprecated-apis>`_ on how to use it.
`#580 <https://github.com/python-attrs/attrs/issues/580>`_
* ``is_callable``: validates that a value is callable .. _`#425`: https://github.com/python-attrs/attrs/issues/425
* ``deep_iterable``: Allows recursion down into an iterable,
applying another validator to every member in the iterable
as well as applying an optional validator to the iterable itself.
* ``deep_mapping``: Allows recursion down into the items in a mapping object,
applying a key validator and a value validator to the key and value in every item.
Also applies an optional validator to the mapping object itself.
You can find them in the ``attr.validators`` package.
`#425 <https://github.com/python-attrs/attrs/issues/425>`_
- Fixed stub files to prevent errors raised by mypy's ``disallow_any_generics = True`` option.
`#443 <https://github.com/python-attrs/attrs/issues/443>`_
- Attributes with ``init=False`` now can follow after ``kw_only=True`` attributes.
`#450 <https://github.com/python-attrs/attrs/issues/450>`_
- ``attrs`` now has first class support for defining exception classes.
If you define a class using ``@attr.s(auto_exc=True)`` and subclass an exception, the class will behave like a well-behaved exception class including an appropriate ``__str__`` method, and all attributes additionally available in an ``args`` attribute.
`#500 <https://github.com/python-attrs/attrs/issues/500>`_
- Clarified documentation for hashing to warn that hashable objects should be deeply immutable (in their usage, even if this is not enforced).
`#503 <https://github.com/python-attrs/attrs/issues/503>`_
`Full changelog <https://www.attrs.org/en/stable/changelog.html>`_. `Full changelog <https://www.attrs.org/en/stable/changelog.html>`_.

View file

@ -0,0 +1,22 @@
attr/__init__.py,sha256=nRvEecOWLaJsMraOK89f4hMYThTUZHWj1B0jl249M-0,1344
attr/__init__.pyi,sha256=5AVtEEzK-g3HO1SUll44hTL8LFoM8TYD7Gn9vEMFGzk,8252
attr/_compat.py,sha256=-pJtdtqgCg0K6rH_BWf3wKuTum58GD-WWPclQQ2SUaU,7326
attr/_config.py,sha256=_KvW0mQdH2PYjHc0YfIUaV_o2pVfM7ziMEYTxwmEhOA,514
attr/_funcs.py,sha256=unAJfNGSTOzxyFzkj7Rs3O1bfsQodmXyir9uZKen-vY,9696
attr/_make.py,sha256=4pdTus8d4OkitzlwytTPP7TNLZK6pVIoKg6KdAZMwYQ,70804
attr/_version.py,sha256=azMi1lNelb3cJvvYUMXsXVbUANkRzbD5IEiaXVpeVr4,2162
attr/_version.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209
attr/converters.py,sha256=5QJRYSXE8G7PW0289y_SPwvvZIcw-nJIuBlfYVdB4BQ,2141
attr/converters.pyi,sha256=wAhCoOT1MFV8t323rpD87O7bxQ8CYLTPiBQd-29BieI,351
attr/exceptions.py,sha256=hbhOa3b4W8_mRrbj3FsMTR4Bt5xzbJs5xaFTWn8s6h4,1635
attr/exceptions.pyi,sha256=4zuaJyl2axxWbqnZgxo_2oTpPNbyowEw3A4hqV5PmAc,458
attr/filters.py,sha256=weDxwATsa69T_0bPVjiM1fGsciAMQmwhY5G8Jm5BxuI,1098
attr/filters.pyi,sha256=xDpmKQlFdssgxGa5tsl1ADh_3zwAwAT4vUhd8h-8-Tk,214
attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
attr/validators.py,sha256=8AsxgdDgh3sGPseiUIMPGcTr6PvaDYfH3AK46tsvs8U,11460
attr/validators.pyi,sha256=vZgsJqUwrJevh4v_Hd7_RSXqDrBctE6-3AEZ7uYKodo,1868
attrs-19.2.0.dist-info/LICENSE,sha256=v2WaKLSSQGAvVrvfSQy-LsUJsVuY-Z17GaUsdA4yeGM,1082
attrs-19.2.0.dist-info/METADATA,sha256=qPqvhqvovqyvpsQebMPTXsOi8pv2xuzUDkUzAxz-wvM,12750
attrs-19.2.0.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
attrs-19.2.0.dist-info/top_level.txt,sha256=tlRYMddkRlKPqJ96wP2_j9uEsmcNHgD2SbuWd4CzGVU,5
attrs-19.2.0.dist-info/RECORD,,

View file

@ -1,5 +1,5 @@
Wheel-Version: 1.0 Wheel-Version: 1.0
Generator: bdist_wheel (0.32.3) Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: true Root-Is-Purelib: true
Tag: py2-none-any Tag: py2-none-any
Tag: py3-none-any Tag: py3-none-any

View file

@ -1,5 +1,5 @@
appdirs==1.4.4 appdirs==1.4.4
attrs==19.1.0 attrs==19.2.0
blessings==1.7 blessings==1.7
cbor2==4.0.1 cbor2==4.0.1
# Though we don't depend on colorama directly, we need to explicitly # Though we don't depend on colorama directly, we need to explicitly

View file

@ -50,9 +50,9 @@ async-timeout==3.0.1 \
# via # via
# aiohttp # aiohttp
# taskcluster # taskcluster
attrs==19.1.0 \ attrs==19.2.0 \
--hash=sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79 \ --hash=sha256:ec20e7a4825331c1b5ebf261d111e16fa9612c1f7a5e1f884f12bd53a664dfd2 \
--hash=sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399 --hash=sha256:f913492e1663d3c36f502e5e9ba6cd13cf19d7fab50aa13239e420fef95e1396
# via # via
# -r requirements-mach-vendor-python.in # -r requirements-mach-vendor-python.in
# aiohttp # aiohttp

View file

@ -1,4 +1,7 @@
pluggy==0.6.0 --hash=sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5 pluggy==0.13.1 --hash=sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d
importlib-metadata==0.23 --hash=sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af
more-itertools==7.2.0 --hash=sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4
zipp==0.6.0 --hash=sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335
py==1.5.4 --hash=sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e py==1.5.4 --hash=sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e
tox==2.7.0 --hash=sha256:0f37ea637ead4a5bbae91531b0bf8fd327c7152e20255e5960ee180598228d21 tox==2.7.0 --hash=sha256:0f37ea637ead4a5bbae91531b0bf8fd327c7152e20255e5960ee180598228d21
virtualenv==15.1.0 --hash=sha256:39d88b533b422825d644087a21e78c45cf5af0ef7a99a1fc9fbb7b481e5c85b0 virtualenv==15.1.0 --hash=sha256:39d88b533b422825d644087a21e78c45cf5af0ef7a99a1fc9fbb7b481e5c85b0