diff --git a/pex/dist_metadata.py b/pex/dist_metadata.py index 6b77ad75a..e3d15cb98 100644 --- a/pex/dist_metadata.py +++ b/pex/dist_metadata.py @@ -449,21 +449,13 @@ def from_packaging_requirement(cls, requirement): url = attr.ib(default=None) # type: Optional[str] extras = attr.ib(default=frozenset()) # type: FrozenSet[str] specifier = attr.ib(factory=SpecifierSet) # type: SpecifierSet - marker = attr.ib(default=None, eq=False) # type: Optional[Marker] + marker = attr.ib(default=None, eq=str) # type: Optional[Marker] project_name = attr.ib(init=False, repr=False) # type: ProjectName - - # We should just be able to set `eq=str` on the marker field, but there is a bug in the - # generated `__hash__` method for this case. It is fixed here in Jan 2022 but the latest - # release (21.4.0) is still from Dec 2021 as of this writing: - # https://github.com/python-attrs/attrs/pull/909 - _marker_for_eq_and_hash = attr.ib(init=False, repr=False) # type: str - _str = attr.ib(init=False, eq=False, repr=False) # type: str def __attrs_post_init__(self): object.__setattr__(self, "project_name", ProjectName(self.name)) - object.__setattr__(self, "_marker_for_eq_and_hash", str(self.marker)) parts = [self.name] if self.extras: diff --git a/pex/vendor/__init__.py b/pex/vendor/__init__.py index 8efac5192..73e1f2e7a 100644 --- a/pex/vendor/__init__.py +++ b/pex/vendor/__init__.py @@ -144,7 +144,14 @@ def iter_vendor_specs(): # We use this for a better @dataclass that is also Python2.7 and PyPy compatible. # N.B.: The `[testenv:typecheck]` section in `tox.ini` should have its deps list updated to # reflect this attrs version. - yield VendorSpec.pinned("attrs", "21.2.0") + # This vcs version gets us the fix in https://github.com/python-attrs/attrs/pull/909 + # which is not yet released. + yield VendorSpec.git( + repo="https://github.com/python-attrs/attrs", + commit="947bfb542104209a587280701d8cb389c813459d", + project_name="attrs", + rewrite=True, + ) # We use this via pex.third_party at runtime to check for compatible wheel tags and at build # time to implement resolving distributions from a PEX repository. diff --git a/pex/vendor/_vendored/attrs/.layout.json b/pex/vendor/_vendored/attrs/.layout.json index b5fedf6f8..7d9254ec3 100644 --- a/pex/vendor/_vendored/attrs/.layout.json +++ b/pex/vendor/_vendored/attrs/.layout.json @@ -1 +1 @@ -{"record_relpath": "attrs-21.2.0.dist-info/RECORD", "stash_dir": ".prefix"} \ No newline at end of file +{"record_relpath": "attrs-21.5.0.dev0.dist-info/RECORD", "stash_dir": ".prefix"} \ No newline at end of file diff --git a/pex/vendor/_vendored/attrs/attr/__init__.py b/pex/vendor/_vendored/attrs/attr/__init__.py index b1ce7fe24..1981d24d4 100644 --- a/pex/vendor/_vendored/attrs/attr/__init__.py +++ b/pex/vendor/_vendored/attrs/attr/__init__.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function import sys @@ -22,7 +24,7 @@ from ._version_info import VersionInfo -__version__ = "21.2.0" +__version__ = "21.5.0.dev0" __version_info__ = VersionInfo._from_version_string(__version__) __title__ = "attrs" @@ -73,6 +75,6 @@ ] if sys.version_info[:2] >= (3, 6): - from ._next_gen import define, field, frozen, mutable + from ._next_gen import define, field, frozen, mutable # noqa: F401 - __all__.extend((define, field, frozen, mutable)) + __all__.extend(("define", "field", "frozen", "mutable")) diff --git a/pex/vendor/_vendored/attrs/attr/__init__.pyi b/pex/vendor/_vendored/attrs/attr/__init__.pyi index 3503b073b..c0a212650 100644 --- a/pex/vendor/_vendored/attrs/attr/__init__.pyi +++ b/pex/vendor/_vendored/attrs/attr/__init__.pyi @@ -24,7 +24,6 @@ from . import setters as setters from . import validators as validators from ._version_info import VersionInfo - __version__: str __version_info__: VersionInfo __title__: str @@ -49,7 +48,10 @@ _OnSetAttrType = Callable[[Any, Attribute[Any], Any], Any] _OnSetAttrArgType = Union[ _OnSetAttrType, List[_OnSetAttrType], setters._NoOpType ] -_FieldTransformer = Callable[[type, List[Attribute[Any]]], List[Attribute[Any]]] +_FieldTransformer = Callable[ + [type, List[Attribute[Any]]], List[Attribute[Any]] +] +_CompareWithType = Callable[[Any, Any], bool] # 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 when passed in a list or tuple. @@ -64,7 +66,6 @@ NOTHING: object # Work around mypy issue #4554 in the common case by using an overload. if sys.version_info >= (3, 8): from typing import Literal - @overload def Factory(factory: Callable[[], _T]) -> _T: ... @overload @@ -77,6 +78,7 @@ if sys.version_info >= (3, 8): factory: Callable[[], _T], takes_self: Literal[False], ) -> _T: ... + else: @overload def Factory(factory: Callable[[], _T]) -> _T: ... @@ -117,7 +119,6 @@ class Attribute(Generic[_T]): type: Optional[Type[_T]] kw_only: bool on_setattr: _OnSetAttrType - def evolve(self, **changes: Any) -> "Attribute[Any]": ... # NOTE: We had several choices for the annotation to use for type arg: @@ -315,6 +316,7 @@ def attrs( getstate_setstate: Optional[bool] = ..., on_setattr: Optional[_OnSetAttrArgType] = ..., field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., ) -> _C: ... @overload @__dataclass_transform__(order_default=True, field_descriptors=(attrib, field)) @@ -341,6 +343,7 @@ def attrs( getstate_setstate: Optional[bool] = ..., on_setattr: Optional[_OnSetAttrArgType] = ..., field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., ) -> Callable[[_C], _C]: ... @overload @__dataclass_transform__(field_descriptors=(attrib, field)) @@ -365,6 +368,7 @@ def define( getstate_setstate: Optional[bool] = ..., on_setattr: Optional[_OnSetAttrArgType] = ..., field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., ) -> _C: ... @overload @__dataclass_transform__(field_descriptors=(attrib, field)) @@ -389,6 +393,7 @@ def define( getstate_setstate: Optional[bool] = ..., on_setattr: Optional[_OnSetAttrArgType] = ..., field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., ) -> Callable[[_C], _C]: ... mutable = define @@ -442,13 +447,17 @@ def make_class( # these: # https://github.com/python/mypy/issues/4236 # https://github.com/python/typing/issues/253 +# XXX: remember to fix attrs.asdict/astuple too! def asdict( inst: Any, recurse: bool = ..., filter: Optional[_FilterType[Any]] = ..., dict_factory: Type[Mapping[Any, Any]] = ..., retain_collection_types: bool = ..., - value_serializer: Optional[Callable[[type, Attribute[Any], Any], Any]] = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: Optional[bool] = ..., ) -> Dict[str, Any]: ... # TODO: add support for returning NamedTuple from the mypy plugin diff --git a/pex/vendor/_vendored/attrs/attr/_cmp.py b/pex/vendor/_vendored/attrs/attr/_cmp.py index b747b603f..6cffa4dba 100644 --- a/pex/vendor/_vendored/attrs/attr/_cmp.py +++ b/pex/vendor/_vendored/attrs/attr/_cmp.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function import functools diff --git a/pex/vendor/_vendored/attrs/attr/_cmp.pyi b/pex/vendor/_vendored/attrs/attr/_cmp.pyi index 7093550f0..e71aaff7a 100644 --- a/pex/vendor/_vendored/attrs/attr/_cmp.pyi +++ b/pex/vendor/_vendored/attrs/attr/_cmp.pyi @@ -2,7 +2,6 @@ from typing import Type from . import _CompareWithType - def cmp_using( eq: Optional[_CompareWithType], lt: Optional[_CompareWithType], diff --git a/pex/vendor/_vendored/attrs/attr/_compat.py b/pex/vendor/_vendored/attrs/attr/_compat.py index 6939f338d..dc0cb02b6 100644 --- a/pex/vendor/_vendored/attrs/attr/_compat.py +++ b/pex/vendor/_vendored/attrs/attr/_compat.py @@ -1,16 +1,22 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function import platform import sys +import threading import types import warnings PY2 = sys.version_info[0] == 2 PYPY = platform.python_implementation() == "PyPy" +PY36 = sys.version_info[:2] >= (3, 6) +HAS_F_STRINGS = PY36 +PY310 = sys.version_info[:2] >= (3, 10) -if PYPY or sys.version_info[:2] >= (3, 6): +if PYPY or PY36: ordered_dict = dict else: from collections import OrderedDict @@ -106,7 +112,6 @@ def just_warn(*args, **kw): # pragma: no cover consequences of not setting the cell on Python 2. """ - else: # Python 3 and later. from collections.abc import Mapping, Sequence # noqa @@ -240,3 +245,17 @@ def func(): set_closure_cell = make_set_closure_cell() + +# Thread-local global to track attrs instances which are already being repr'd. +# This is needed because there is no other (thread-safe) way to pass info +# about the instances that are already being repr'd through the call stack +# in order to ensure we don't perform infinite recursion. +# +# For instance, if an instance contains a dict which contains that instance, +# we need to know that we're already repr'ing the outside instance from within +# the dict's repr() call. +# +# This lives here rather than in _make.py so that the functions in _make.py +# don't have a direct reference to the thread-local in their globals dict. +# If they have such a reference, it breaks cloudpickle. +repr_context = threading.local() diff --git a/pex/vendor/_vendored/attrs/attr/_config.py b/pex/vendor/_vendored/attrs/attr/_config.py index 8ec920962..fc9be29d0 100644 --- a/pex/vendor/_vendored/attrs/attr/_config.py +++ b/pex/vendor/_vendored/attrs/attr/_config.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function @@ -9,6 +11,10 @@ def set_run_validators(run): """ Set whether or not validators are run. By default, they are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` + instead. """ if not isinstance(run, bool): raise TypeError("'run' must be bool.") @@ -19,5 +25,9 @@ def set_run_validators(run): def get_run_validators(): """ Return whether or not validators are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` + instead. """ return _run_validators diff --git a/pex/vendor/_vendored/attrs/attr/_funcs.py b/pex/vendor/_vendored/attrs/attr/_funcs.py index fda508c5c..4c90085a4 100644 --- a/pex/vendor/_vendored/attrs/attr/_funcs.py +++ b/pex/vendor/_vendored/attrs/attr/_funcs.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function import copy @@ -25,7 +27,7 @@ def asdict( ``attrs``-decorated. :param callable filter: A callable whose return code determines whether an attribute or element is included (``True``) or dropped (``False``). Is - called with the `attr.Attribute` as the first argument and the + called with the `attrs.Attribute` as the first argument and the value as the second argument. :param callable dict_factory: A callable to produce dictionaries from. For example, to produce ordered dictionaries instead of normal Python @@ -46,6 +48,8 @@ def asdict( .. versionadded:: 16.0.0 *dict_factory* .. versionadded:: 16.1.0 *retain_collection_types* .. versionadded:: 20.3.0 *value_serializer* + .. versionadded:: 21.3.0 If a dict has a collection for a key, it is + serialized as a tuple. """ attrs = fields(inst.__class__) rv = dict_factory() @@ -61,11 +65,11 @@ def asdict( if has(v.__class__): rv[a.name] = asdict( v, - True, - filter, - dict_factory, - retain_collection_types, - value_serializer, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ) elif isinstance(v, (tuple, list, set, frozenset)): cf = v.__class__ if retain_collection_types is True else list @@ -73,10 +77,11 @@ def asdict( [ _asdict_anything( i, - filter, - dict_factory, - retain_collection_types, - value_serializer, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ) for i in v ] @@ -87,17 +92,19 @@ def asdict( ( _asdict_anything( kk, - filter, - df, - retain_collection_types, - value_serializer, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ), _asdict_anything( vv, - filter, - df, - retain_collection_types, - value_serializer, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ), ) for kk, vv in iteritems(v) @@ -111,6 +118,7 @@ def asdict( def _asdict_anything( val, + is_key, filter, dict_factory, retain_collection_types, @@ -123,22 +131,29 @@ def _asdict_anything( # Attrs class. rv = asdict( val, - True, - filter, - dict_factory, - retain_collection_types, - value_serializer, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ) elif isinstance(val, (tuple, list, set, frozenset)): - cf = val.__class__ if retain_collection_types is True else list + if retain_collection_types is True: + cf = val.__class__ + elif is_key: + cf = tuple + else: + cf = list + rv = cf( [ _asdict_anything( i, - filter, - dict_factory, - retain_collection_types, - value_serializer, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ) for i in val ] @@ -148,10 +163,20 @@ def _asdict_anything( rv = df( ( _asdict_anything( - kk, filter, df, retain_collection_types, value_serializer + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ), _asdict_anything( - vv, filter, df, retain_collection_types, value_serializer + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, ), ) for kk, vv in iteritems(val) @@ -181,7 +206,7 @@ def astuple( ``attrs``-decorated. :param callable filter: A callable whose return code determines whether an attribute or element is included (``True``) or dropped (``False``). Is - called with the `attr.Attribute` as the first argument and the + called with the `attrs.Attribute` as the first argument and the value as the second argument. :param callable tuple_factory: A callable to produce tuples from. For example, to produce lists instead of tuples. @@ -291,7 +316,9 @@ def assoc(inst, **changes): class. .. deprecated:: 17.1.0 - Use `evolve` instead. + Use `attrs.evolve` instead if you can. + This function will not be removed du to the slightly different approach + compared to `attrs.evolve`. """ import warnings @@ -370,18 +397,16 @@ class and you didn't pass any attribs. :raise NameError: If types cannot be resolved because of missing variables. :returns: *cls* so you can use this function also as a class decorator. - Please note that you have to apply it **after** `attr.s`. That means - the decorator has to come in the line **before** `attr.s`. + Please note that you have to apply it **after** `attrs.define`. That + means the decorator has to come in the line **before** `attrs.define`. .. versionadded:: 20.1.0 .. versionadded:: 21.1.0 *attribs* """ - try: - # Since calling get_type_hints is expensive we cache whether we've - # done it already. - cls.__attrs_types_resolved__ - except AttributeError: + # Since calling get_type_hints is expensive we cache whether we've + # done it already. + if getattr(cls, "__attrs_types_resolved__", None) != cls: import typing hints = typing.get_type_hints(cls, globalns=globalns, localns=localns) @@ -389,7 +414,9 @@ class and you didn't pass any attribs. if field.name in hints: # Since fields have been frozen we must work around it. _obj_setattr(field, "type", hints[field.name]) - cls.__attrs_types_resolved__ = True + # We store the class we resolved so that subclasses know they haven't + # been resolved. + cls.__attrs_types_resolved__ = cls # Return the class so you can use it as a decorator too. return cls diff --git a/pex/vendor/_vendored/attrs/attr/_make.py b/pex/vendor/_vendored/attrs/attr/_make.py index a1912b123..19a354204 100644 --- a/pex/vendor/_vendored/attrs/attr/_make.py +++ b/pex/vendor/_vendored/attrs/attr/_make.py @@ -1,18 +1,22 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function import copy import inspect import linecache import sys -import threading -import uuid import warnings from operator import itemgetter -from . import _config, setters +# We need to import _compat itself in addition to the _compat members to avoid +# having the thread-local in the globals here. +from . import _compat, _config, setters from ._compat import ( + HAS_F_STRINGS, PY2, + PY310, PYPY, isclass, iteritems, @@ -57,6 +61,8 @@ # Unique object for unequivocal getattr() defaults. _sentinel = object() +_ng_default_on_setattr = setters.pipe(setters.convert, setters.validate) + class _Nothing(object): """ @@ -143,11 +149,11 @@ def attrib( is used and no value is passed while instantiating or the attribute is excluded using ``init=False``. - If the value is an instance of `Factory`, its callable will be + If the value is an instance of `attrs.Factory`, its callable will be used to construct a new value (useful for mutable data types like lists or dicts). - If a default is not set (or set manually to `attr.NOTHING`), a value + If a default is not set (or set manually to `attrs.NOTHING`), a value *must* be supplied when instantiating; otherwise a `TypeError` will be raised. @@ -160,7 +166,7 @@ def attrib( :param validator: `callable` that is called by ``attrs``-generated ``__init__`` methods after the instance has been initialized. They - receive the initialized instance, the `Attribute`, and the + receive the initialized instance, the :func:`~attrs.Attribute`, and the passed value. The return value is *not* inspected so the validator has to throw an @@ -233,10 +239,10 @@ def attrib( parameter is ignored). :param on_setattr: Allows to overwrite the *on_setattr* setting from `attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used. - Set to `attr.setters.NO_OP` to run **no** `setattr` hooks for this + Set to `attrs.setters.NO_OP` to run **no** `setattr` hooks for this attribute -- regardless of the setting in `attr.s`. :type on_setattr: `callable`, or a list of callables, or `None`, or - `attr.setters.NO_OP` + `attrs.setters.NO_OP` .. versionadded:: 15.2.0 *convert* .. versionadded:: 16.3.0 *metadata* @@ -319,24 +325,31 @@ def _compile_and_eval(script, globs, locs=None, filename=""): eval(bytecode, globs, locs) -def _make_method(name, script, filename, globs=None): +def _make_method(name, script, filename, globs): """ Create the method with the script given and return the method object. """ locs = {} - if globs is None: - globs = {} - - _compile_and_eval(script, globs, locs, filename) # In order of debuggers like PDB being able to step through the code, # we add a fake linecache entry. - linecache.cache[filename] = ( - len(script), - None, - script.splitlines(True), - filename, - ) + count = 1 + base_filename = filename + while True: + linecache_tuple = ( + len(script), + None, + script.splitlines(True), + filename, + ) + old_val = linecache.cache.setdefault(filename, linecache_tuple) + if old_val == linecache_tuple: + break + else: + filename = "{}-{}>".format(base_filename[:-1], count) + count += 1 + + _compile_and_eval(script, globs, locs, filename) return locs[name] @@ -571,15 +584,11 @@ def _transform_attrs( cls, {a.name for a in own_attrs} ) - attr_names = [a.name for a in base_attrs + own_attrs] - - AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) - if kw_only: own_attrs = [a.evolve(kw_only=True) for a in own_attrs] base_attrs = [a.evolve(kw_only=True) for a in base_attrs] - attrs = AttrsClass(base_attrs + own_attrs) + attrs = base_attrs + own_attrs # Mandatory vs non-mandatory attr order only matters when they are part of # the __init__ signature and when they aren't kw_only (which are moved to @@ -598,7 +607,13 @@ def _transform_attrs( if field_transformer is not None: attrs = field_transformer(cls, attrs) - return _Attributes((attrs, base_attrs, base_attr_map)) + + # Create AttrsClass *after* applying the field_transformer since it may + # add or remove attributes! + attr_names = [a.name for a in attrs] + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + + return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map)) if PYPY: @@ -616,7 +631,6 @@ def _frozen_setattrs(self, name, value): raise FrozenInstanceError() - else: def _frozen_setattrs(self, name, value): @@ -654,7 +668,7 @@ class _ClassBuilder(object): "_on_setattr", "_slots", "_weakref_slot", - "_has_own_setattr", + "_wrote_own_setattr", "_has_custom_setattr", ) @@ -701,7 +715,7 @@ def __init__( self._on_setattr = on_setattr self._has_custom_setattr = has_custom_setattr - self._has_own_setattr = False + self._wrote_own_setattr = False self._cls_dict["__attrs_attrs__"] = self._attrs @@ -709,7 +723,33 @@ def __init__( self._cls_dict["__setattr__"] = _frozen_setattrs self._cls_dict["__delattr__"] = _frozen_delattrs - self._has_own_setattr = True + self._wrote_own_setattr = True + elif on_setattr in ( + _ng_default_on_setattr, + setters.validate, + setters.convert, + ): + has_validator = has_converter = False + for a in attrs: + if a.validator is not None: + has_validator = True + if a.converter is not None: + has_converter = True + + if has_validator and has_converter: + break + if ( + ( + on_setattr == _ng_default_on_setattr + and not (has_validator or has_converter) + ) + or (on_setattr == setters.validate and not has_validator) + or (on_setattr == setters.convert and not has_converter) + ): + # If class-level on_setattr is set to convert + validate, but + # there's no field to convert or validate, pretend like there's + # no on_setattr. + self._on_setattr = None if getstate_setstate: ( @@ -759,13 +799,13 @@ def _patch_original_class(self): # If we've inherited an attrs __setattr__ and don't write our own, # reset it to object's. - if not self._has_own_setattr and getattr( + if not self._wrote_own_setattr and getattr( cls, "__attrs_own_setattr__", False ): cls.__attrs_own_setattr__ = False if not self._has_custom_setattr: - cls.__setattr__ = object.__setattr__ + cls.__setattr__ = _obj_setattr return cls @@ -787,13 +827,13 @@ def _create_slots_class(self): # XXX: a non-attrs class and subclass the resulting class with an attrs # XXX: class. See `test_slotted_confused` for details. For now that's # XXX: OK with us. - if not self._has_own_setattr: + if not self._wrote_own_setattr: cd["__attrs_own_setattr__"] = False if not self._has_custom_setattr: for base_cls in self._cls.__bases__: if base_cls.__dict__.get("__attrs_own_setattr__", False): - cd["__setattr__"] = object.__setattr__ + cd["__setattr__"] = _obj_setattr break # Traverse the MRO to collect existing slots @@ -826,7 +866,7 @@ def _create_slots_class(self): slot_names = [name for name in names if name not in base_names] # There are slots for attributes from current class # that are defined in parent classes. - # As their descriptors may be overriden by a child class, + # As their descriptors may be overridden by a child class, # we collect them here and update the class dict reused_slots = { slot: slot_descriptor @@ -847,7 +887,7 @@ def _create_slots_class(self): cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) # The following is a fix for - # https://github.com/python-attrs/attrs/issues/102. On Python 3, + # . On Python 3, # if a method mentions `__class__` or uses the no-arg super(), the # compiler will bake a reference to the class in the method itself # as `method.__closure__`. Since we replace the class with a @@ -879,7 +919,7 @@ def _create_slots_class(self): def add_repr(self, ns): self._cls_dict["__repr__"] = self._add_method_dunders( - _make_repr(self._attrs, ns=ns) + _make_repr(self._attrs, ns, self._cls) ) return self @@ -958,14 +998,20 @@ def add_init(self): self._cache_hash, self._base_attr_map, self._is_exc, - self._on_setattr is not None - and self._on_setattr is not setters.NO_OP, + self._on_setattr, attrs_init=False, ) ) return self + def add_match_args(self): + self._cls_dict["__match_args__"] = tuple( + field.name + for field in self._attrs + if field.init and not field.kw_only + ) + def add_attrs_init(self): self._cls_dict["__attrs_init__"] = self._add_method_dunders( _make_init( @@ -978,8 +1024,7 @@ def add_attrs_init(self): self._cache_hash, self._base_attr_map, self._is_exc, - self._on_setattr is not None - and self._on_setattr is not setters.NO_OP, + self._on_setattr, attrs_init=True, ) ) @@ -1038,7 +1083,7 @@ def __setattr__(self, name, val): self._cls_dict["__attrs_own_setattr__"] = True self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) - self._has_own_setattr = True + self._wrote_own_setattr = True return self @@ -1192,6 +1237,7 @@ def attrs( getstate_setstate=None, on_setattr=None, field_transformer=None, + match_args=True, ): r""" A class decorator that adds `dunder @@ -1240,7 +1286,7 @@ def attrs( *cmp*, or *hash* overrides whatever *auto_detect* would determine. *auto_detect* requires Python 3. Setting it ``True`` on Python 2 raises - a `PythonTooOldError`. + an `attrs.exceptions.PythonTooOldError`. :param bool repr: Create a ``__repr__`` method with a human readable representation of ``attrs`` attributes.. @@ -1327,7 +1373,7 @@ def attrs( If you assign a value to those attributes (e.g. ``x: int = 42``), that value becomes the default value like if it were passed using - ``attr.ib(default=42)``. Passing an instance of `Factory` also + ``attr.ib(default=42)``. Passing an instance of `attrs.Factory` also works as expected in most cases (see warning below). Attributes annotated as `typing.ClassVar`, and attributes that are @@ -1369,7 +1415,7 @@ def attrs( :param bool collect_by_mro: Setting this to `True` fixes the way ``attrs`` collects attributes from base classes. The default behavior is incorrect in certain cases of multiple inheritance. It should be on by - default but is kept off for backward-compatability. + default but is kept off for backward-compatibility. See issue `#428 `_ for more details. @@ -1399,7 +1445,7 @@ def attrs( the callable. If a list of callables is passed, they're automatically wrapped in an - `attr.setters.pipe`. + `attrs.setters.pipe`. :param Optional[callable] field_transformer: A function that is called with the original class object and all @@ -1407,6 +1453,13 @@ def attrs( this, e.g., to automatically add converters or validators to fields based on their types. See `transform-fields` for more details. + :param bool match_args: + If `True` (default), set ``__match_args__`` on the class to support + `PEP 634 `_ (Structural + Pattern Matching). It is a tuple of all positional-only ``__init__`` + parameter names on Python 3.10 and later. Ignored on older Python + versions. + .. versionadded:: 16.0.0 *slots* .. versionadded:: 16.1.0 *frozen* .. versionadded:: 16.3.0 *str* @@ -1440,6 +1493,7 @@ def attrs( ``init=False`` injects ``__attrs_init__`` .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 21.3.0 *match_args* """ if auto_detect and PY2: raise PythonTooOldError( @@ -1556,6 +1610,13 @@ def wrap(cls): " init must be True." ) + if ( + PY310 + and match_args + and not _has_own_attribute(cls, "__match_args__") + ): + builder.add_match_args() + return builder.build_class() # maybe_cls's type depends on the usage of the decorator. It's a class @@ -1586,7 +1647,6 @@ def _has_frozen_base_class(cls): and cls.__setattr__.__name__ == _frozen_setattrs.__name__ ) - else: def _has_frozen_base_class(cls): @@ -1601,30 +1661,12 @@ def _generate_unique_filename(cls, func_name): """ Create a "filename" suitable for a function being generated. """ - unique_id = uuid.uuid4() - extra = "" - count = 1 - - while True: - unique_filename = "".format( - func_name, - cls.__module__, - getattr(cls, "__qualname__", cls.__name__), - extra, - ) - # To handle concurrency we essentially "reserve" our spot in - # the linecache with a dummy line. The caller can then - # set this value correctly. - cache_line = (1, None, (str(unique_id),), unique_filename) - if ( - linecache.cache.setdefault(unique_filename, cache_line) - == cache_line - ): - return unique_filename - - # Looks like this spot is taken. Try again. - count += 1 - extra = "-{0}".format(count) + unique_filename = "".format( + func_name, + cls.__module__, + getattr(cls, "__qualname__", cls.__name__), + ) + return unique_filename def _make_hash(cls, attrs, frozen, cache_hash): @@ -1636,6 +1678,8 @@ def _make_hash(cls, attrs, frozen, cache_hash): unique_filename = _generate_unique_filename(cls, "hash") type_hash = hash(unique_filename) + # If eq is custom generated, we need to include the functions in globs + globs = {} hash_def = "def __hash__(self" hash_func = "hash((" @@ -1670,7 +1714,14 @@ def append_hash_computation_lines(prefix, indent): ) for a in attrs: - method_lines.append(indent + " self.%s," % a.name) + if a.eq_key: + cmp_name = "_%s_key" % (a.name,) + globs[cmp_name] = a.eq_key + method_lines.append( + indent + " %s(self.%s)," % (cmp_name, a.name) + ) + else: + method_lines.append(indent + " self.%s," % a.name) method_lines.append(indent + " " + closing_braces) @@ -1690,7 +1741,7 @@ def append_hash_computation_lines(prefix, indent): append_hash_computation_lines("return ", tab) script = "\n".join(method_lines) - return _make_method("__hash__", script, unique_filename) + return _make_method("__hash__", script, unique_filename, globs) def _add_hash(cls, attrs): @@ -1841,66 +1892,134 @@ def _add_eq(cls, attrs=None): return cls -_already_repring = threading.local() +if HAS_F_STRINGS: + def _make_repr(attrs, ns, cls): + unique_filename = _generate_unique_filename(cls, "repr") + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, (repr if a.repr is True else a.repr), a.init) + for a in attrs + if a.repr is not False + ) + globs = { + name + "_repr": r + for name, r, _ in attr_names_with_reprs + if r != repr + } + globs["_compat"] = _compat + globs["AttributeError"] = AttributeError + globs["NOTHING"] = NOTHING + attribute_fragments = [] + for name, r, i in attr_names_with_reprs: + accessor = ( + "self." + name + if i + else 'getattr(self, "' + name + '", NOTHING)' + ) + fragment = ( + "%s={%s!r}" % (name, accessor) + if r == repr + else "%s={%s_repr(%s)}" % (name, name, accessor) + ) + attribute_fragments.append(fragment) + repr_fragment = ", ".join(attribute_fragments) -def _make_repr(attrs, ns): - """ - Make a repr method that includes relevant *attrs*, adding *ns* to the full - name. - """ + if ns is None: + cls_name_fragment = ( + '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' + ) + else: + cls_name_fragment = ns + ".{self.__class__.__name__}" + + lines = [ + "def __repr__(self):", + " try:", + " already_repring = _compat.repr_context.already_repring", + " except AttributeError:", + " already_repring = {id(self),}", + " _compat.repr_context.already_repring = already_repring", + " else:", + " if id(self) in already_repring:", + " return '...'", + " else:", + " already_repring.add(id(self))", + " try:", + " return f'%s(%s)'" % (cls_name_fragment, repr_fragment), + " finally:", + " already_repring.remove(id(self))", + ] + + return _make_method( + "__repr__", "\n".join(lines), unique_filename, globs=globs + ) - # Figure out which attributes to include, and which function to use to - # format them. The a.repr value can be either bool or a custom callable. - attr_names_with_reprs = tuple( - (a.name, repr if a.repr is True else a.repr) - for a in attrs - if a.repr is not False - ) +else: - def __repr__(self): + def _make_repr(attrs, ns, _): """ - Automatically created by attrs. + Make a repr method that includes relevant *attrs*, adding *ns* to the + full name. """ - try: - working_set = _already_repring.working_set - except AttributeError: - working_set = set() - _already_repring.working_set = working_set - if id(self) in working_set: - return "..." - real_cls = self.__class__ - if ns is None: - qualname = getattr(real_cls, "__qualname__", None) - if qualname is not None: - class_name = qualname.rsplit(">.", 1)[-1] - else: - class_name = real_cls.__name__ - else: - class_name = ns + "." + real_cls.__name__ + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, repr if a.repr is True else a.repr) + for a in attrs + if a.repr is not False + ) - # Since 'self' remains on the stack (i.e.: strongly referenced) for the - # duration of this call, it's safe to depend on id(...) stability, and - # not need to track the instance and therefore worry about properties - # like weakref- or hash-ability. - working_set.add(id(self)) - try: - result = [class_name, "("] - first = True - for name, attr_repr in attr_names_with_reprs: - if first: - first = False + def __repr__(self): + """ + Automatically created by attrs. + """ + try: + already_repring = _compat.repr_context.already_repring + except AttributeError: + already_repring = set() + _compat.repr_context.already_repring = already_repring + + if id(self) in already_repring: + return "..." + real_cls = self.__class__ + if ns is None: + qualname = getattr(real_cls, "__qualname__", None) + if qualname is not None: # pragma: no cover + # This case only happens on Python 3.5 and 3.6. We exclude + # it from coverage, because we don't want to slow down our + # test suite by running them under coverage too for this + # one line. + class_name = qualname.rsplit(">.", 1)[-1] else: - result.append(", ") - result.extend( - (name, "=", attr_repr(getattr(self, name, NOTHING))) - ) - return "".join(result) + ")" - finally: - working_set.remove(id(self)) + class_name = real_cls.__name__ + else: + class_name = ns + "." + real_cls.__name__ + + # Since 'self' remains on the stack (i.e.: strongly referenced) + # for the duration of this call, it's safe to depend on id(...) + # stability, and not need to track the instance and therefore + # worry about properties like weakref- or hash-ability. + already_repring.add(id(self)) + try: + result = [class_name, "("] + first = True + for name, attr_repr in attr_names_with_reprs: + if first: + first = False + else: + result.append(", ") + result.extend( + (name, "=", attr_repr(getattr(self, name, NOTHING))) + ) + return "".join(result) + ")" + finally: + already_repring.remove(id(self)) - return __repr__ + return __repr__ def _add_repr(cls, ns=None, attrs=None): @@ -1910,7 +2029,7 @@ def _add_repr(cls, ns=None, attrs=None): if attrs is None: attrs = cls.__attrs_attrs__ - cls.__repr__ = _make_repr(attrs, ns) + cls.__repr__ = _make_repr(attrs, ns, cls) return cls @@ -1927,7 +2046,7 @@ def fields(cls): :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` class. - :rtype: tuple (with name accessors) of `attr.Attribute` + :rtype: tuple (with name accessors) of `attrs.Attribute` .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields by name. @@ -1954,7 +2073,7 @@ def fields_dict(cls): class. :rtype: an ordered dict where keys are attribute names and values are - `attr.Attribute`\\ s. This will be a `dict` if it's + `attrs.Attribute`\\ s. This will be a `dict` if it's naturally ordered like on Python 3.6+ or an :class:`~collections.OrderedDict` otherwise. @@ -2008,10 +2127,14 @@ def _make_init( cache_hash, base_attr_map, is_exc, - has_global_on_setattr, + cls_on_setattr, attrs_init, ): - if frozen and has_global_on_setattr: + has_cls_on_setattr = ( + cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP + ) + + if frozen and has_cls_on_setattr: raise ValueError("Frozen classes can't use on_setattr.") needs_cached_setattr = cache_hash or frozen @@ -2029,9 +2152,7 @@ def _make_init( raise ValueError("Frozen classes can't use on_setattr.") needs_cached_setattr = True - elif ( - has_global_on_setattr and a.on_setattr is not setters.NO_OP - ) or _is_slot_attr(a.name, base_attr_map): + elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: needs_cached_setattr = True unique_filename = _generate_unique_filename(cls, "init") @@ -2045,8 +2166,7 @@ def _make_init( cache_hash, base_attr_map, is_exc, - needs_cached_setattr, - has_global_on_setattr, + has_cls_on_setattr, attrs_init, ) if cls.__module__ in sys.modules: @@ -2058,7 +2178,7 @@ def _make_init( if needs_cached_setattr: # Save the lookup overhead in __init__ if we need to circumvent # setattr hooks. - globs["_cached_setattr"] = _obj_setattr + globs["_setattr"] = _obj_setattr init = _make_method( "__attrs_init__" if attrs_init else "__init__", @@ -2075,7 +2195,7 @@ def _setattr(attr_name, value_var, has_on_setattr): """ Use the cached object.setattr to set *attr_name* to *value_var*. """ - return "_setattr('%s', %s)" % (attr_name, value_var) + return "_setattr(self, '%s', %s)" % (attr_name, value_var) def _setattr_with_converter(attr_name, value_var, has_on_setattr): @@ -2083,7 +2203,7 @@ def _setattr_with_converter(attr_name, value_var, has_on_setattr): Use the cached object.setattr to set *attr_name* to *value_var*, but run its converter first. """ - return "_setattr('%s', %s(%s))" % ( + return "_setattr(self, '%s', %s(%s))" % ( attr_name, _init_converter_pat % (attr_name,), value_var, @@ -2182,8 +2302,7 @@ def _attrs_to_init_script( cache_hash, base_attr_map, is_exc, - needs_cached_setattr, - has_global_on_setattr, + has_cls_on_setattr, attrs_init, ): """ @@ -2198,14 +2317,6 @@ def _attrs_to_init_script( if pre_init: lines.append("self.__attrs_pre_init__()") - if needs_cached_setattr: - lines.append( - # Circumvent the __setattr__ descriptor to save one lookup per - # assignment. - # Note _setattr will be used again below if cache_hash is True - "_setattr = _cached_setattr.__get__(self, self.__class__)" - ) - if frozen is True: if slots is True: fmt_setter = _setattr @@ -2257,7 +2368,7 @@ def fmt_setter_with_converter( attr_name = a.name has_on_setattr = a.on_setattr is not None or ( - a.on_setattr is not setters.NO_OP and has_global_on_setattr + a.on_setattr is not setters.NO_OP and has_cls_on_setattr ) arg_name = a.name.lstrip("_") @@ -2421,7 +2532,7 @@ def fmt_setter_with_converter( if post_init: lines.append("self.__attrs_post_init__()") - # because this is set only after __attrs_post_init is called, a crash + # because this is set only after __attrs_post_init__ is called, a crash # will result if post-init tries to access the hash code. This seemed # preferable to setting this beforehand, in which case alteration to # field values during post-init combined with post-init accessing the @@ -2430,7 +2541,7 @@ def fmt_setter_with_converter( if frozen: if slots: # if frozen and slots, then _setattr defined above - init_hash_cache = "_setattr('%s', %s)" + init_hash_cache = "_setattr(self, '%s', %s)" else: # if frozen and not slots, then _inst_dict defined above init_hash_cache = "_inst_dict['%s'] = %s" @@ -2474,19 +2585,26 @@ class Attribute(object): """ *Read-only* representation of an attribute. + The class has *all* arguments of `attr.ib` (except for ``factory`` + which is only syntactic sugar for ``default=Factory(...)`` plus the + following: + + - ``name`` (`str`): The name of the attribute. + - ``inherited`` (`bool`): Whether or not that attribute has been inherited + from a base class. + - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The callables + that are used for comparing and ordering objects by this attribute, + respectively. These are set by passing a callable to `attr.ib`'s ``eq``, + ``order``, or ``cmp`` arguments. See also :ref:`comparison customization + `. + Instances of this class are frequently used for introspection purposes like: - `fields` returns a tuple of them. - Validators get them passed as the first argument. - - The *field transformer* hook receives a list of them. - - :attribute name: The name of the attribute. - :attribute inherited: Whether or not that attribute has been inherited from - a base class. - - Plus *all* arguments of `attr.ib` (except for ``factory`` - which is only syntactic sugar for ``default=Factory(...)``. + - The :ref:`field transformer ` hook receives a list of + them. .. versionadded:: 20.1.0 *inherited* .. versionadded:: 20.1.0 *on_setattr* @@ -2832,7 +2950,7 @@ class Factory(object): """ Stores a factory callable. - If passed as the default value to `attr.ib`, the factory is used to + If passed as the default value to `attrs.field`, the factory is used to generate a new value. :param callable factory: A callable that takes either none or exactly one diff --git a/pex/vendor/_vendored/attrs/attr/_next_gen.py b/pex/vendor/_vendored/attrs/attr/_next_gen.py index 15ad6c376..87bcef830 100644 --- a/pex/vendor/_vendored/attrs/attr/_next_gen.py +++ b/pex/vendor/_vendored/attrs/attr/_next_gen.py @@ -1,18 +1,24 @@ +# SPDX-License-Identifier: MIT + """ These are Python 3.6+-only and keyword-only APIs that call `attr.s` and `attr.ib` with different default values. """ -from functools import partial - -if "__PEX_UNVENDORED__" in __import__("os").environ: - from attr.exceptions import UnannotatedAttributeError # vendor:skip -else: - from pex.third_party.attr.exceptions import UnannotatedAttributeError +from functools import partial from . import setters -from ._make import NOTHING, _frozen_setattrs, attrib, attrs +from ._funcs import asdict as _asdict +from ._funcs import astuple as _astuple +from ._make import ( + NOTHING, + _frozen_setattrs, + _ng_default_on_setattr, + attrib, + attrs, +) +from .exceptions import UnannotatedAttributeError def define( @@ -36,22 +42,40 @@ def define( getstate_setstate=None, on_setattr=None, field_transformer=None, + match_args=True, ): r""" - The only behavioral differences are the handling of the *auto_attribs* - option: + Define an ``attrs`` class. + + Differences to the classic `attr.s` that it uses underneath: + + - Automatically detect whether or not *auto_attribs* should be `True` + (c.f. *auto_attribs* parameter). + - If *frozen* is `False`, run converters and validators when setting an + attribute by default. + - *slots=True* (see :term:`slotted classes` for potentially surprising + behaviors) + - *auto_exc=True* + - *auto_detect=True* + - *order=False* + - Some options that were only relevant on Python 2 or were kept around for + backwards-compatibility have been removed. + + Please note that these are all defaults and you can change them as you + wish. :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves exactly like `attr.s`. If left `None`, `attr.s` will try to guess: - 1. If any attributes are annotated and no unannotated `attr.ib`\ s + 1. If any attributes are annotated and no unannotated `attrs.fields`\ s are found, it assumes *auto_attribs=True*. 2. Otherwise it assumes *auto_attribs=False* and tries to collect - `attr.ib`\ s. + `attrs.fields`\ s. - and that mutable classes (``frozen=False``) validate on ``__setattr__``. + For now, please refer to `attr.s` for the rest of the parameters. .. versionadded:: 20.1.0 + .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. """ def do_it(cls, auto_attribs): @@ -76,6 +100,7 @@ def do_it(cls, auto_attribs): getstate_setstate=getstate_setstate, on_setattr=on_setattr, field_transformer=field_transformer, + match_args=match_args, ) def wrap(cls): @@ -88,9 +113,9 @@ def wrap(cls): had_on_setattr = on_setattr not in (None, setters.NO_OP) - # By default, mutable classes validate on setattr. + # By default, mutable classes convert & validate on setattr. if frozen is False and on_setattr is None: - on_setattr = setters.validate + on_setattr = _ng_default_on_setattr # However, if we subclass a frozen class, we inherit the immutability # and disable on_setattr. @@ -160,3 +185,31 @@ def field( order=order, on_setattr=on_setattr, ) + + +def asdict(inst, *, recurse=True, filter=None, value_serializer=None): + """ + Same as `attr.asdict`, except that collections types are always retained + and dict is always used as *dict_factory*. + + .. versionadded:: 21.3.0 + """ + return _asdict( + inst=inst, + recurse=recurse, + filter=filter, + value_serializer=value_serializer, + retain_collection_types=True, + ) + + +def astuple(inst, *, recurse=True, filter=None): + """ + Same as `attr.astuple`, except that collections types are always retained + and `tuple` is always used as the *tuple_factory*. + + .. versionadded:: 21.3.0 + """ + return _astuple( + inst=inst, recurse=recurse, filter=filter, retain_collection_types=True + ) diff --git a/pex/vendor/_vendored/attrs/attr/_version_info.py b/pex/vendor/_vendored/attrs/attr/_version_info.py index 014e78a1b..cdaeec37a 100644 --- a/pex/vendor/_vendored/attrs/attr/_version_info.py +++ b/pex/vendor/_vendored/attrs/attr/_version_info.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function from functools import total_ordering diff --git a/pex/vendor/_vendored/attrs/attr/converters.py b/pex/vendor/_vendored/attrs/attr/converters.py index 2777db6d0..1fb6c05d7 100644 --- a/pex/vendor/_vendored/attrs/attr/converters.py +++ b/pex/vendor/_vendored/attrs/attr/converters.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + """ Commonly useful converters. """ @@ -14,9 +16,10 @@ __all__ = [ - "pipe", - "optional", "default_if_none", + "optional", + "pipe", + "to_bool", ] @@ -65,14 +68,14 @@ def default_if_none(default=NOTHING, factory=None): result of *factory*. :param default: Value to be used if ``None`` is passed. Passing an instance - of `attr.Factory` is supported, however the ``takes_self`` option + of `attrs.Factory` is supported, however the ``takes_self`` option is *not*. :param callable factory: A callable that takes no parameters whose result is used if ``None`` is passed. :raises TypeError: If **neither** *default* or *factory* is passed. :raises TypeError: If **both** *default* and *factory* are passed. - :raises ValueError: If an instance of `attr.Factory` is passed with + :raises ValueError: If an instance of `attrs.Factory` is passed with ``takes_self=True``. .. versionadded:: 18.2.0 @@ -109,3 +112,44 @@ def default_if_none_converter(val): return default return default_if_none_converter + + +def to_bool(val): + """ + Convert "boolean" strings (e.g., from env. vars.) to real booleans. + + Values mapping to :code:`True`: + + - :code:`True` + - :code:`"true"` / :code:`"t"` + - :code:`"yes"` / :code:`"y"` + - :code:`"on"` + - :code:`"1"` + - :code:`1` + + Values mapping to :code:`False`: + + - :code:`False` + - :code:`"false"` / :code:`"f"` + - :code:`"no"` / :code:`"n"` + - :code:`"off"` + - :code:`"0"` + - :code:`0` + + :raises ValueError: for any other value. + + .. versionadded:: 21.3.0 + """ + if isinstance(val, str): + val = val.lower() + truthy = {True, "true", "t", "yes", "y", "on", "1", 1} + falsy = {False, "false", "f", "no", "n", "off", "0", 0} + try: + if val in truthy: + return True + if val in falsy: + return False + except TypeError: + # Raised when "val" is not hashable (e.g., lists) + pass + raise ValueError("Cannot convert value to bool: {}".format(val)) diff --git a/pex/vendor/_vendored/attrs/attr/converters.pyi b/pex/vendor/_vendored/attrs/attr/converters.pyi index 84a57590b..0f58088a3 100644 --- a/pex/vendor/_vendored/attrs/attr/converters.pyi +++ b/pex/vendor/_vendored/attrs/attr/converters.pyi @@ -2,7 +2,6 @@ from typing import Callable, Optional, TypeVar, overload from . import _ConverterType - _T = TypeVar("_T") def pipe(*validators: _ConverterType) -> _ConverterType: ... @@ -11,3 +10,4 @@ def optional(converter: _ConverterType) -> _ConverterType: ... def default_if_none(default: _T) -> _ConverterType: ... @overload def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType: ... +def to_bool(val: str) -> bool: ... diff --git a/pex/vendor/_vendored/attrs/attr/exceptions.py b/pex/vendor/_vendored/attrs/attr/exceptions.py index f6f9861be..b2f1edc32 100644 --- a/pex/vendor/_vendored/attrs/attr/exceptions.py +++ b/pex/vendor/_vendored/attrs/attr/exceptions.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + from __future__ import absolute_import, division, print_function diff --git a/pex/vendor/_vendored/attrs/attr/exceptions.pyi b/pex/vendor/_vendored/attrs/attr/exceptions.pyi index a800fb26b..f2680118b 100644 --- a/pex/vendor/_vendored/attrs/attr/exceptions.pyi +++ b/pex/vendor/_vendored/attrs/attr/exceptions.pyi @@ -1,6 +1,5 @@ from typing import Any - class FrozenError(AttributeError): msg: str = ... diff --git a/pex/vendor/_vendored/attrs/attr/filters.py b/pex/vendor/_vendored/attrs/attr/filters.py index dc47e8fa3..a1978a877 100644 --- a/pex/vendor/_vendored/attrs/attr/filters.py +++ b/pex/vendor/_vendored/attrs/attr/filters.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + """ Commonly useful filters for `attr.asdict`. """ @@ -20,10 +22,10 @@ def _split_what(what): def include(*what): """ - Whitelist *what*. + Include *what*. - :param what: What to whitelist. - :type what: `list` of `type` or `attr.Attribute`\\ s + :param what: What to include. + :type what: `list` of `type` or `attrs.Attribute`\\ s :rtype: `callable` """ @@ -37,10 +39,10 @@ def include_(attribute, value): def exclude(*what): """ - Blacklist *what*. + Exclude *what*. - :param what: What to blacklist. - :type what: `list` of classes or `attr.Attribute`\\ s. + :param what: What to exclude. + :type what: `list` of classes or `attrs.Attribute`\\ s. :rtype: `callable` """ diff --git a/pex/vendor/_vendored/attrs/attr/filters.pyi b/pex/vendor/_vendored/attrs/attr/filters.pyi index f7b63f1bb..993866865 100644 --- a/pex/vendor/_vendored/attrs/attr/filters.pyi +++ b/pex/vendor/_vendored/attrs/attr/filters.pyi @@ -2,6 +2,5 @@ from typing import Any, Union from . import Attribute, _FilterType - def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ... def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ... diff --git a/pex/vendor/_vendored/attrs/attr/setters.py b/pex/vendor/_vendored/attrs/attr/setters.py index 240014b3c..b1cbb5d83 100644 --- a/pex/vendor/_vendored/attrs/attr/setters.py +++ b/pex/vendor/_vendored/attrs/attr/setters.py @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: MIT + """ Commonly used hooks for on_setattr. """ diff --git a/pex/vendor/_vendored/attrs/attr/setters.pyi b/pex/vendor/_vendored/attrs/attr/setters.pyi index a921e07de..3f5603c2b 100644 --- a/pex/vendor/_vendored/attrs/attr/setters.pyi +++ b/pex/vendor/_vendored/attrs/attr/setters.pyi @@ -2,7 +2,6 @@ from typing import Any, NewType, NoReturn, TypeVar, cast from . import Attribute, _OnSetAttrType - _T = TypeVar("_T") def frozen( diff --git a/pex/vendor/_vendored/attrs/attr/validators.py b/pex/vendor/_vendored/attrs/attr/validators.py index b9a73054e..0b0c8342f 100644 --- a/pex/vendor/_vendored/attrs/attr/validators.py +++ b/pex/vendor/_vendored/attrs/attr/validators.py @@ -1,28 +1,96 @@ +# SPDX-License-Identifier: MIT + """ Commonly useful validators. """ from __future__ import absolute_import, division, print_function +import operator import re +from contextlib import contextmanager + +from ._config import get_run_validators, set_run_validators from ._make import _AndValidator, and_, attrib, attrs from .exceptions import NotCallableError +try: + Pattern = re.Pattern +except AttributeError: # Python <3.7 lacks a Pattern type. + Pattern = type(re.compile("")) + + __all__ = [ "and_", "deep_iterable", "deep_mapping", + "disabled", + "ge", + "get_disabled", + "gt", "in_", "instance_of", "is_callable", + "le", + "lt", "matches_re", + "max_len", "optional", "provides", + "set_disabled", ] +def set_disabled(disabled): + """ + Globally disable or enable running validators. + + By default, they are run. + + :param disabled: If ``True``, disable running all validators. + :type disabled: bool + + .. warning:: + + This function is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(not disabled) + + +def get_disabled(): + """ + Return a bool indicating whether validators are currently disabled or not. + + :return: ``True`` if validators are currently disabled. + :rtype: bool + + .. versionadded:: 21.3.0 + """ + return not get_run_validators() + + +@contextmanager +def disabled(): + """ + Context manager that disables running validators within its context. + + .. warning:: + + This context manager is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(False) + try: + yield + finally: + set_run_validators(True) + + @attrs(repr=False, slots=True, hash=True) class _InstanceOfValidator(object): type = attrib() @@ -61,7 +129,7 @@ def instance_of(type): :type type: type or tuple of types :raises TypeError: With a human readable error message, the attribute - (of type `attr.Attribute`), the expected type, and the value it + (of type `attrs.Attribute`), the expected type, and the value it got. """ return _InstanceOfValidator(type) @@ -69,8 +137,7 @@ def instance_of(type): @attrs(repr=False, frozen=True, slots=True) class _MatchesReValidator(object): - regex = attrib() - flags = attrib() + pattern = attrib() match_func = attrib() def __call__(self, inst, attr, value): @@ -79,18 +146,18 @@ def __call__(self, inst, attr, value): """ if not self.match_func(value): raise ValueError( - "'{name}' must match regex {regex!r}" + "'{name}' must match regex {pattern!r}" " ({value!r} doesn't)".format( - name=attr.name, regex=self.regex.pattern, value=value + name=attr.name, pattern=self.pattern.pattern, value=value ), attr, - self.regex, + self.pattern, value, ) def __repr__(self): - return "".format( - regex=self.regex + return "".format( + pattern=self.pattern ) @@ -99,7 +166,7 @@ def matches_re(regex, flags=0, func=None): 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 regex: a regex string or precompiled pattern 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 @@ -109,34 +176,44 @@ def matches_re(regex, flags=0, func=None): but on a pre-`re.compile`\ ed pattern. .. versionadded:: 19.2.0 + .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. """ 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." - % ( + "'func' must be one of {}.".format( ", ".join( sorted( e and e.__name__ or "None" for e in set(valid_funcs) ) - ), + ) ) ) - pattern = re.compile(regex, flags) + if isinstance(regex, Pattern): + if flags: + raise TypeError( + "'flags' can only be used with a string pattern; " + "pass flags to re.compile() instead" + ) + pattern = regex + else: + 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 + elif fullmatch: + match_func = pattern.fullmatch + else: # Python 2 fullmatch emulation (https://bugs.python.org/issue16203) + pattern = re.compile( + r"(?:{})\Z".format(pattern.pattern), pattern.flags + ) + match_func = pattern.match - return _MatchesReValidator(pattern, flags, match_func) + return _MatchesReValidator(pattern, match_func) @attrs(repr=False, slots=True, hash=True) @@ -175,7 +252,7 @@ def provides(interface): :type interface: ``zope.interface.Interface`` :raises TypeError: With a human readable error message, the attribute - (of type `attr.Attribute`), the expected interface, and the + (of type `attrs.Attribute`), the expected interface, and the value it got. """ return _ProvidesValidator(interface) @@ -248,7 +325,7 @@ def in_(options): :type options: list, tuple, `enum.Enum`, ... :raises ValueError: With a human readable error message, the attribute (of - type `attr.Attribute`), the expected options, and the value it + type `attrs.Attribute`), the expected options, and the value it got. .. versionadded:: 17.1.0 @@ -287,7 +364,7 @@ def is_callable(): .. versionadded:: 19.1.0 :raises `attr.exceptions.NotCallableError`: With a human readable error - message containing the attribute (`attr.Attribute`) name, + message containing the attribute (`attrs.Attribute`) name, and the value it got. """ return _IsCallableValidator() @@ -377,3 +454,108 @@ def deep_mapping(key_validator, value_validator, mapping_validator=None): :raises TypeError: if any sub-validators fail """ return _DeepMapping(key_validator, value_validator, mapping_validator) + + +@attrs(repr=False, frozen=True, slots=True) +class _NumberValidator(object): + bound = attrib() + compare_op = attrib() + compare_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.compare_func(value, self.bound): + raise ValueError( + "'{name}' must be {op} {bound}: {value}".format( + name=attr.name, + op=self.compare_op, + bound=self.bound, + value=value, + ) + ) + + def __repr__(self): + return "".format( + op=self.compare_op, bound=self.bound + ) + + +def lt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number larger or equal to *val*. + + :param val: Exclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<", operator.lt) + + +def le(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number greater than *val*. + + :param val: Inclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<=", operator.le) + + +def ge(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller than *val*. + + :param val: Inclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">=", operator.ge) + + +def gt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller or equal to *val*. + + :param val: Exclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">", operator.gt) + + +@attrs(repr=False, frozen=True, slots=True) +class _MaxLengthValidator(object): + max_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) > self.max_length: + raise ValueError( + "Length of '{name}' must be <= {max}: {len}".format( + name=attr.name, max=self.max_length, len=len(value) + ) + ) + + def __repr__(self): + return "".format(max=self.max_length) + + +def max_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is longer than *length*. + + :param int length: Maximum length of the string or iterable + + .. versionadded:: 21.3.0 + """ + return _MaxLengthValidator(length) diff --git a/pex/vendor/_vendored/attrs/attr/validators.pyi b/pex/vendor/_vendored/attrs/attr/validators.pyi index fe92aac42..5e00b8543 100644 --- a/pex/vendor/_vendored/attrs/attr/validators.pyi +++ b/pex/vendor/_vendored/attrs/attr/validators.pyi @@ -3,11 +3,13 @@ from typing import ( AnyStr, Callable, Container, + ContextManager, Iterable, List, Mapping, Match, Optional, + Pattern, Tuple, Type, TypeVar, @@ -17,7 +19,6 @@ from typing import ( from . import _ValidatorType - _T = TypeVar("_T") _T1 = TypeVar("_T1") _T2 = TypeVar("_T2") @@ -27,6 +28,10 @@ _K = TypeVar("_K") _V = TypeVar("_V") _M = TypeVar("_M", bound=Mapping) +def set_disabled(run: bool) -> None: ... +def get_disabled() -> bool: ... +def disabled() -> ContextManager[None]: ... + # 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 @@ -50,7 +55,7 @@ def optional( def in_(options: Container[_T]) -> _ValidatorType[_T]: ... def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... def matches_re( - regex: AnyStr, + regex: Union[Pattern[AnyStr], AnyStr], flags: int = ..., func: Optional[ Callable[[AnyStr, AnyStr, int], Optional[Match[AnyStr]]] @@ -66,3 +71,8 @@ def deep_mapping( mapping_validator: Optional[_ValidatorType[_M]] = ..., ) -> _ValidatorType[_M]: ... def is_callable() -> _ValidatorType[_T]: ... +def lt(val: _T) -> _ValidatorType[_T]: ... +def le(val: _T) -> _ValidatorType[_T]: ... +def ge(val: _T) -> _ValidatorType[_T]: ... +def gt(val: _T) -> _ValidatorType[_T]: ... +def max_len(length: int) -> _ValidatorType[_T]: ... diff --git a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/top_level.txt b/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/top_level.txt deleted file mode 100644 index 66a062d88..000000000 --- a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -attr diff --git a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/AUTHORS.rst b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/AUTHORS.rst similarity index 100% rename from pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/AUTHORS.rst rename to pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/AUTHORS.rst diff --git a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/INSTALLER b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/INSTALLER similarity index 100% rename from pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/INSTALLER rename to pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/INSTALLER diff --git a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/LICENSE b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/LICENSE similarity index 100% rename from pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/LICENSE rename to pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/LICENSE diff --git a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/METADATA b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/METADATA similarity index 69% rename from pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/METADATA rename to pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/METADATA index ceca5b9ad..22975cb9f 100644 --- a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/METADATA +++ b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: attrs -Version: 21.2.0 +Version: 21.5.0.dev0 Summary: Classes Without Boilerplate Home-page: https://www.attrs.org/ Author: Hynek Schlawack @@ -16,7 +16,6 @@ Project-URL: Funding, https://github.com/sponsors/hynek Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi Project-URL: Ko-fi, https://ko-fi.com/the_hynek Keywords: class,attribute,boilerplate -Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Natural Language :: English @@ -37,6 +36,8 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: AUTHORS.rst Provides-Extra: dev Requires-Dist: coverage[toml] (>=5.0.2) ; extra == 'dev' Requires-Dist: hypothesis ; extra == 'dev' @@ -50,6 +51,7 @@ Requires-Dist: furo ; extra == 'dev' Requires-Dist: sphinx ; extra == 'dev' Requires-Dist: sphinx-notfound-page ; extra == 'dev' Requires-Dist: pre-commit ; extra == 'dev' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'dev' Provides-Extra: docs Requires-Dist: furo ; extra == 'docs' Requires-Dist: sphinx ; extra == 'docs' @@ -64,6 +66,7 @@ Requires-Dist: six ; extra == 'tests' Requires-Dist: mypy ; extra == 'tests' Requires-Dist: pytest-mypy-plugins ; extra == 'tests' Requires-Dist: zope.interface ; extra == 'tests' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'tests' Provides-Extra: tests_no_zope Requires-Dist: coverage[toml] (>=5.0.2) ; extra == 'tests_no_zope' Requires-Dist: hypothesis ; extra == 'tests_no_zope' @@ -72,14 +75,16 @@ Requires-Dist: pytest (>=4.3.0) ; extra == 'tests_no_zope' Requires-Dist: six ; extra == 'tests_no_zope' Requires-Dist: mypy ; extra == 'tests_no_zope' Requires-Dist: pytest-mypy-plugins ; extra == 'tests_no_zope' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'tests_no_zope' -====================================== -``attrs``: Classes Without Boilerplate -====================================== +.. image:: https://www.attrs.org/en/stable/_static/attrs_logo.png + :alt: attrs logo + :align: center -``attrs`` is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka `dunder `_ methods). -`Trusted by NASA `_ for Mars missions since 2020! + +``attrs`` is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka `dunder methods `_). +`Trusted by NASA `_ for Mars missions since 2020! Its main goal is to help you to write **concise** and **correct** software without slowing down your code. @@ -91,12 +96,12 @@ For that, it gives you a class decorator and a way to declaratively define the a .. code-block:: pycon - >>> import attr + >>> from attrs import asdict, define, make_class, Factory - >>> @attr.s - ... class SomeClass(object): - ... a_number = attr.ib(default=42) - ... list_of_numbers = attr.ib(factory=list) + >>> @define + ... class SomeClass: + ... a_number: int = 42 + ... list_of_numbers: list[int] = Factory(list) ... ... def hard_math(self, another_number): ... return self.a_number + sum(self.list_of_numbers) * another_number @@ -113,13 +118,13 @@ For that, it gives you a class decorator and a way to declaratively define the a >>> sc != SomeClass(2, [3, 2, 1]) True - >>> attr.asdict(sc) + >>> asdict(sc) {'a_number': 1, 'list_of_numbers': [1, 2, 3]} >>> SomeClass() SomeClass(a_number=42, list_of_numbers=[]) - >>> C = attr.make_class("C", ["a", "b"]) + >>> C = make_class("C", ["a", "b"]) >>> C("foo", "bar") C(a='foo', b='bar') @@ -128,17 +133,33 @@ After *declaring* your attributes ``attrs`` gives you: - a concise and explicit overview of the class's attributes, - a nice human-readable ``__repr__``, -- a complete set of comparison methods (equality and ordering), +- equality-checking methods, - an initializer, - and much more, *without* writing dull boilerplate code again and again and *without* runtime performance penalties. -On Python 3.6 and later, you can often even drop the calls to ``attr.ib()`` by using `type annotations `_. +**Hate type annotations**!? +No problem! +Types are entirely **optional** with ``attrs``. +Simply assign ``attrs.field()`` to the attributes instead of annotating them with types. + +---- + +This example uses ``attrs``'s modern APIs that have been introduced in version 20.1.0, and the ``attrs`` package import name that has been added in version 21.3.0. +The classic APIs (``@attr.s``, ``attr.ib``, plus their serious business aliases) and the ``attr`` package import name will remain **indefinitely**. + +Please check out `On The Core API Names `_ for a more in-depth explanation. + -This gives you the power to use actual classes with actual types in your code instead of confusing ``tuple``\ s or `confusingly behaving `_ ``namedtuple``\ s. -Which in turn encourages you to write *small classes* that do `one thing well `_. -Never again violate the `single responsibility principle `_ just because implementing ``__init__`` et al is a painful drag. +Data Classes +============ + +On the tin, ``attrs`` might remind you of ``dataclasses`` (and indeed, ``dataclasses`` `are a descendant `_ of ``attrs``). +In practice it does a lot more and is more flexible. +For instance it allows you to define `special handling of NumPy arrays for equality checks `_, or allows more ways to `plug into the initialization process `_. + +For more details, please refer to our `comparison page `_. .. -getting-help- @@ -146,7 +167,7 @@ Never again violate the `single responsibility principle `_ to get help. +Please use the ``python-attrs`` tag on `Stack Overflow `_ to get help. Answering questions of your fellow developers is also a great way to help the project! @@ -165,7 +186,7 @@ It’s rigorously tested on Python 2.7, 3.5+, and PyPy. We collect information on **third-party extensions** in our `wiki `_. Feel free to browse and add your own! -If you'd like to contribute to ``attrs`` you're most welcome and we've written `a little guide `_ to get you started! +If you'd like to contribute to ``attrs`` you're most welcome and we've written `a little guide `_ to get you started! ``attrs`` for Enterprise @@ -181,18 +202,17 @@ Save time, reduce risk, and improve code health, while paying the maintainers of Release Information =================== -21.2.0 (2021-05-07) +21.4.0 (2021-12-29) ------------------- -Backward-incompatible Changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changes +^^^^^^^ -- We had to revert the recursive feature for ``attr.evolve()`` because it broke some use-cases -- sorry! - `#806 `_ -- Python 3.4 is now blocked using packaging metadata because ``attrs`` can't be imported on it anymore. - To ensure that 3.4 users can keep installing ``attrs`` easily, we will `yank `_ 21.1.0 from PyPI. - This has **no** consequences if you pin ``attrs`` to 21.1.0. - `#807 `_ +- Fixed the test suite on PyPy3.8 where ``cloudpickle`` does not work. + `#892 `_ +- Fixed ``coverage report`` for projects that use ``attrs`` and don't set a ``--source``. + `#895 `_, + `#896 `_ `Full changelog `_. @@ -207,5 +227,3 @@ A full list of contributors can be found in `GitHub's overview `_ and aspires to fix some of it clunkiness and unfortunate decisions. Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay? - - diff --git a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/REQUESTED b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/REQUESTED similarity index 100% rename from pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/REQUESTED rename to pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/REQUESTED diff --git a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/WHEEL b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/WHEEL similarity index 70% rename from pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/WHEEL rename to pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/WHEEL index 01b8fc7d4..0b18a2811 100644 --- a/pex/vendor/_vendored/attrs/attrs-21.2.0.dist-info/WHEEL +++ b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/WHEEL @@ -1,5 +1,5 @@ Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) +Generator: bdist_wheel (0.37.1) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any diff --git a/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/direct_url.json b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/direct_url.json new file mode 100644 index 000000000..16c9c07af --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/direct_url.json @@ -0,0 +1 @@ +{"url": "https://github.com/python-attrs/attrs", "vcs_info": {"commit_id": "947bfb542104209a587280701d8cb389c813459d", "requested_revision": "947bfb542104209a587280701d8cb389c813459d", "vcs": "git"}} \ No newline at end of file diff --git a/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/top_level.txt b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/top_level.txt new file mode 100644 index 000000000..eca8ba9f0 --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/top_level.txt @@ -0,0 +1,2 @@ +attr +attrs diff --git a/pex/vendor/_vendored/attrs/attrs/__init__.py b/pex/vendor/_vendored/attrs/attrs/__init__.py new file mode 100644 index 000000000..d89e53a44 --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs/__init__.py @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: MIT + +if "__PEX_UNVENDORED__" in __import__("os").environ: + from attr import ( + NOTHING, + Attribute, + Factory, + __author__, + __copyright__, + __description__, + __doc__, + __email__, + __license__, + __title__, + __url__, + __version__, + __version_info__, + assoc, + cmp_using, + define, + evolve, + field, + fields, + fields_dict, + frozen, + has, + make_class, + mutable, + resolve_types, + validate, +) # vendor:skip +else: + from pex.third_party.attr import ( + NOTHING, + Attribute, + Factory, + __author__, + __copyright__, + __description__, + __doc__, + __email__, + __license__, + __title__, + __url__, + __version__, + __version_info__, + assoc, + cmp_using, + define, + evolve, + field, + fields, + fields_dict, + frozen, + has, + make_class, + mutable, + resolve_types, + validate, +) + +if "__PEX_UNVENDORED__" in __import__("os").environ: + from attr._next_gen import asdict, astuple # vendor:skip +else: + from pex.third_party.attr._next_gen import asdict, astuple + + +from . import converters, exceptions, filters, setters, validators + + +__all__ = [ + "__author__", + "__copyright__", + "__description__", + "__doc__", + "__email__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "asdict", + "assoc", + "astuple", + "Attribute", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "Factory", + "field", + "fields_dict", + "fields", + "filters", + "frozen", + "has", + "make_class", + "mutable", + "NOTHING", + "resolve_types", + "setters", + "validate", + "validators", +] diff --git a/pex/vendor/_vendored/attrs/attrs/__init__.pyi b/pex/vendor/_vendored/attrs/attrs/__init__.pyi new file mode 100644 index 000000000..7426fa5dd --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs/__init__.pyi @@ -0,0 +1,63 @@ +from typing import ( + Any, + Callable, + Dict, + Mapping, + Optional, + Sequence, + Tuple, + Type, +) + +# Because we need to type our own stuff, we have to make everything from +# attr explicitly public too. +from attr import __author__ as __author__ +from attr import __copyright__ as __copyright__ +from attr import __description__ as __description__ +from attr import __email__ as __email__ +from attr import __license__ as __license__ +from attr import __title__ as __title__ +from attr import __url__ as __url__ +from attr import __version__ as __version__ +from attr import __version_info__ as __version_info__ +from attr import _FilterType +from attr import assoc as assoc +from attr import Attribute as Attribute +from attr import define as define +from attr import evolve as evolve +from attr import Factory as Factory +from attr import exceptions as exceptions +from attr import field as field +from attr import fields as fields +from attr import fields_dict as fields_dict +from attr import frozen as frozen +from attr import has as has +from attr import make_class as make_class +from attr import mutable as mutable +from attr import NOTHING as NOTHING +from attr import resolve_types as resolve_types +from attr import setters as setters +from attr import validate as validate +from attr import validators as validators + +# TODO: see definition of attr.asdict/astuple +def asdict( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + dict_factory: Type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: bool = ..., +) -> Dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + tuple_factory: Type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> Tuple[Any, ...]: ... diff --git a/pex/vendor/_vendored/attrs/attrs/converters.py b/pex/vendor/_vendored/attrs/attrs/converters.py new file mode 100644 index 000000000..c68e3928f --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs/converters.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +if "__PEX_UNVENDORED__" in __import__("os").environ: + from attr.converters import * # vendor:skip +else: + from pex.third_party.attr.converters import * +# noqa diff --git a/pex/vendor/_vendored/attrs/attrs/exceptions.py b/pex/vendor/_vendored/attrs/attrs/exceptions.py new file mode 100644 index 000000000..b6169f532 --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs/exceptions.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +if "__PEX_UNVENDORED__" in __import__("os").environ: + from attr.exceptions import * # vendor:skip +else: + from pex.third_party.attr.exceptions import * +# noqa diff --git a/pex/vendor/_vendored/attrs/attrs/filters.py b/pex/vendor/_vendored/attrs/attrs/filters.py new file mode 100644 index 000000000..eaa377e81 --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs/filters.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +if "__PEX_UNVENDORED__" in __import__("os").environ: + from attr.filters import * # vendor:skip +else: + from pex.third_party.attr.filters import * +# noqa diff --git a/pex/vendor/_vendored/attrs/attrs/py.typed b/pex/vendor/_vendored/attrs/attrs/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/pex/vendor/_vendored/attrs/attrs/setters.py b/pex/vendor/_vendored/attrs/attrs/setters.py new file mode 100644 index 000000000..18f04c7cc --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs/setters.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +if "__PEX_UNVENDORED__" in __import__("os").environ: + from attr.setters import * # vendor:skip +else: + from pex.third_party.attr.setters import * +# noqa diff --git a/pex/vendor/_vendored/attrs/attrs/validators.py b/pex/vendor/_vendored/attrs/attrs/validators.py new file mode 100644 index 000000000..bb7dbd7f9 --- /dev/null +++ b/pex/vendor/_vendored/attrs/attrs/validators.py @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +if "__PEX_UNVENDORED__" in __import__("os").environ: + from attr.validators import * # vendor:skip +else: + from pex.third_party.attr.validators import * +# noqa diff --git a/pex/vendor/_vendored/attrs/constraints.txt b/pex/vendor/_vendored/attrs/constraints.txt deleted file mode 100644 index 931dfaf9f..000000000 --- a/pex/vendor/_vendored/attrs/constraints.txt +++ /dev/null @@ -1 +0,0 @@ -attrs==21.2.0 diff --git a/tox.ini b/tox.ini index 3f0a8be3f..a71728323 100644 --- a/tox.ini +++ b/tox.ini @@ -82,7 +82,8 @@ commands = [testenv:typecheck] deps = - attrs==21.2.0 # This version should track the version in pex/vendor/__init__.py. + # This version should track the version in pex/vendor/__init__.py. + attrs @ git+https://github.com/python-attrs/attrs@947bfb542104209a587280701d8cb389c813459d packaging==20.9 # This version should track the version in pex/vendor/__init__.py. pip==20.3.4 # This version should track the version in pex/vendor/__init__.py. setuptools==44.0.0 # This version should track the version in pex/vendor/__init__.py.