externals: add attrs
for new jsonschema
Updating `jsonschema` to 3.2.0 requires `attrs`. Add it to externals.
This commit is contained in:
parent
90592b3cbe
commit
f83e0fb81a
@ -38,6 +38,10 @@ PackageName: argparse
|
|||||||
PackageHomePage: https://pypi.python.org/pypi/argparse
|
PackageHomePage: https://pypi.python.org/pypi/argparse
|
||||||
PackageLicenseDeclared: Python-2.0
|
PackageLicenseDeclared: Python-2.0
|
||||||
|
|
||||||
|
PackageName: attrs
|
||||||
|
PackageHomePage: https://github.com/python-attrs/attrs
|
||||||
|
PackageLicenseDeclared: MIT
|
||||||
|
|
||||||
PackageName: ctest_log_parser
|
PackageName: ctest_log_parser
|
||||||
PackageHomePage: https://github.com/Kitware/CMake
|
PackageHomePage: https://github.com/Kitware/CMake
|
||||||
PackageLicenseDeclared: BSD-3-Clause
|
PackageLicenseDeclared: BSD-3-Clause
|
||||||
|
7
lib/spack/external/__init__.py
vendored
7
lib/spack/external/__init__.py
vendored
@ -24,6 +24,13 @@
|
|||||||
vendored copy ever needs to be updated again:
|
vendored copy ever needs to be updated again:
|
||||||
https://github.com/spack/spack/pull/6786/commits/dfcef577b77249106ea4e4c69a6cd9e64fa6c418
|
https://github.com/spack/spack/pull/6786/commits/dfcef577b77249106ea4e4c69a6cd9e64fa6c418
|
||||||
|
|
||||||
|
attrs
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* Homepage: https://github.com/python-attrs/attrs
|
||||||
|
* Usage: Needed by jsonschema.
|
||||||
|
* Version: 21.2.0 (83d3cd70f90a3f4d19ee8b508e58d1c58821c0ad)
|
||||||
|
|
||||||
ctest_log_parser
|
ctest_log_parser
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
21
lib/spack/external/attr/LICENSE
vendored
Normal file
21
lib/spack/external/attr/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Hynek Schlawack
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
78
lib/spack/external/attr/__init__.py
vendored
Normal file
78
lib/spack/external/attr/__init__.py
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from . import converters, exceptions, filters, setters, validators
|
||||||
|
from ._cmp import cmp_using
|
||||||
|
from ._config import get_run_validators, set_run_validators
|
||||||
|
from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
|
||||||
|
from ._make import (
|
||||||
|
NOTHING,
|
||||||
|
Attribute,
|
||||||
|
Factory,
|
||||||
|
attrib,
|
||||||
|
attrs,
|
||||||
|
fields,
|
||||||
|
fields_dict,
|
||||||
|
make_class,
|
||||||
|
validate,
|
||||||
|
)
|
||||||
|
from ._version_info import VersionInfo
|
||||||
|
|
||||||
|
|
||||||
|
__version__ = "21.2.0"
|
||||||
|
__version_info__ = VersionInfo._from_version_string(__version__)
|
||||||
|
|
||||||
|
__title__ = "attrs"
|
||||||
|
__description__ = "Classes Without Boilerplate"
|
||||||
|
__url__ = "https://www.attrs.org/"
|
||||||
|
__uri__ = __url__
|
||||||
|
__doc__ = __description__ + " <" + __uri__ + ">"
|
||||||
|
|
||||||
|
__author__ = "Hynek Schlawack"
|
||||||
|
__email__ = "hs@ox.cx"
|
||||||
|
|
||||||
|
__license__ = "MIT"
|
||||||
|
__copyright__ = "Copyright (c) 2015 Hynek Schlawack"
|
||||||
|
|
||||||
|
|
||||||
|
s = attributes = attrs
|
||||||
|
ib = attr = attrib
|
||||||
|
dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"Attribute",
|
||||||
|
"Factory",
|
||||||
|
"NOTHING",
|
||||||
|
"asdict",
|
||||||
|
"assoc",
|
||||||
|
"astuple",
|
||||||
|
"attr",
|
||||||
|
"attrib",
|
||||||
|
"attributes",
|
||||||
|
"attrs",
|
||||||
|
"cmp_using",
|
||||||
|
"converters",
|
||||||
|
"evolve",
|
||||||
|
"exceptions",
|
||||||
|
"fields",
|
||||||
|
"fields_dict",
|
||||||
|
"filters",
|
||||||
|
"get_run_validators",
|
||||||
|
"has",
|
||||||
|
"ib",
|
||||||
|
"make_class",
|
||||||
|
"resolve_types",
|
||||||
|
"s",
|
||||||
|
"set_run_validators",
|
||||||
|
"setters",
|
||||||
|
"validate",
|
||||||
|
"validators",
|
||||||
|
]
|
||||||
|
|
||||||
|
if sys.version_info[:2] >= (3, 6):
|
||||||
|
from ._next_gen import define, field, frozen, mutable
|
||||||
|
|
||||||
|
__all__.extend((define, field, frozen, mutable))
|
152
lib/spack/external/attr/_cmp.py
vendored
Normal file
152
lib/spack/external/attr/_cmp.py
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from ._compat import new_class
|
||||||
|
from ._make import _make_ne
|
||||||
|
|
||||||
|
|
||||||
|
_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="}
|
||||||
|
|
||||||
|
|
||||||
|
def cmp_using(
|
||||||
|
eq=None,
|
||||||
|
lt=None,
|
||||||
|
le=None,
|
||||||
|
gt=None,
|
||||||
|
ge=None,
|
||||||
|
require_same_type=True,
|
||||||
|
class_name="Comparable",
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Create a class that can be passed into `attr.ib`'s ``eq``, ``order``, and
|
||||||
|
``cmp`` arguments to customize field comparison.
|
||||||
|
|
||||||
|
The resulting class will have a full set of ordering methods if
|
||||||
|
at least one of ``{lt, le, gt, ge}`` and ``eq`` are provided.
|
||||||
|
|
||||||
|
:param Optional[callable] eq: `callable` used to evaluate equality
|
||||||
|
of two objects.
|
||||||
|
:param Optional[callable] lt: `callable` used to evaluate whether
|
||||||
|
one object is less than another object.
|
||||||
|
:param Optional[callable] le: `callable` used to evaluate whether
|
||||||
|
one object is less than or equal to another object.
|
||||||
|
:param Optional[callable] gt: `callable` used to evaluate whether
|
||||||
|
one object is greater than another object.
|
||||||
|
:param Optional[callable] ge: `callable` used to evaluate whether
|
||||||
|
one object is greater than or equal to another object.
|
||||||
|
|
||||||
|
:param bool require_same_type: When `True`, equality and ordering methods
|
||||||
|
will return `NotImplemented` if objects are not of the same type.
|
||||||
|
|
||||||
|
:param Optional[str] class_name: Name of class. Defaults to 'Comparable'.
|
||||||
|
|
||||||
|
See `comparison` for more details.
|
||||||
|
|
||||||
|
.. versionadded:: 21.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"__slots__": ["value"],
|
||||||
|
"__init__": _make_init(),
|
||||||
|
"_requirements": [],
|
||||||
|
"_is_comparable_to": _is_comparable_to,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add operations.
|
||||||
|
num_order_functions = 0
|
||||||
|
has_eq_function = False
|
||||||
|
|
||||||
|
if eq is not None:
|
||||||
|
has_eq_function = True
|
||||||
|
body["__eq__"] = _make_operator("eq", eq)
|
||||||
|
body["__ne__"] = _make_ne()
|
||||||
|
|
||||||
|
if lt is not None:
|
||||||
|
num_order_functions += 1
|
||||||
|
body["__lt__"] = _make_operator("lt", lt)
|
||||||
|
|
||||||
|
if le is not None:
|
||||||
|
num_order_functions += 1
|
||||||
|
body["__le__"] = _make_operator("le", le)
|
||||||
|
|
||||||
|
if gt is not None:
|
||||||
|
num_order_functions += 1
|
||||||
|
body["__gt__"] = _make_operator("gt", gt)
|
||||||
|
|
||||||
|
if ge is not None:
|
||||||
|
num_order_functions += 1
|
||||||
|
body["__ge__"] = _make_operator("ge", ge)
|
||||||
|
|
||||||
|
type_ = new_class(class_name, (object,), {}, lambda ns: ns.update(body))
|
||||||
|
|
||||||
|
# Add same type requirement.
|
||||||
|
if require_same_type:
|
||||||
|
type_._requirements.append(_check_same_type)
|
||||||
|
|
||||||
|
# Add total ordering if at least one operation was defined.
|
||||||
|
if 0 < num_order_functions < 4:
|
||||||
|
if not has_eq_function:
|
||||||
|
# functools.total_ordering requires __eq__ to be defined,
|
||||||
|
# so raise early error here to keep a nice stack.
|
||||||
|
raise ValueError(
|
||||||
|
"eq must be define is order to complete ordering from "
|
||||||
|
"lt, le, gt, ge."
|
||||||
|
)
|
||||||
|
type_ = functools.total_ordering(type_)
|
||||||
|
|
||||||
|
return type_
|
||||||
|
|
||||||
|
|
||||||
|
def _make_init():
|
||||||
|
"""
|
||||||
|
Create __init__ method.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
"""
|
||||||
|
Initialize object with *value*.
|
||||||
|
"""
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
return __init__
|
||||||
|
|
||||||
|
|
||||||
|
def _make_operator(name, func):
|
||||||
|
"""
|
||||||
|
Create operator method.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def method(self, other):
|
||||||
|
if not self._is_comparable_to(other):
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
result = func(self.value, other.value)
|
||||||
|
if result is NotImplemented:
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
method.__name__ = "__%s__" % (name,)
|
||||||
|
method.__doc__ = "Return a %s b. Computed by attrs." % (
|
||||||
|
_operation_names[name],
|
||||||
|
)
|
||||||
|
|
||||||
|
return method
|
||||||
|
|
||||||
|
|
||||||
|
def _is_comparable_to(self, other):
|
||||||
|
"""
|
||||||
|
Check whether `other` is comparable to `self`.
|
||||||
|
"""
|
||||||
|
for func in self._requirements:
|
||||||
|
if not func(self, other):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _check_same_type(self, other):
|
||||||
|
"""
|
||||||
|
Return True if *self* and *other* are of the same type, False otherwise.
|
||||||
|
"""
|
||||||
|
return other.value.__class__ is self.value.__class__
|
242
lib/spack/external/attr/_compat.py
vendored
Normal file
242
lib/spack/external/attr/_compat.py
vendored
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
|
PY2 = sys.version_info[0] == 2
|
||||||
|
PYPY = platform.python_implementation() == "PyPy"
|
||||||
|
|
||||||
|
|
||||||
|
if PYPY or sys.version_info[:2] >= (3, 6):
|
||||||
|
ordered_dict = dict
|
||||||
|
else:
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
ordered_dict = OrderedDict
|
||||||
|
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
from collections import Mapping, Sequence
|
||||||
|
|
||||||
|
from UserDict import IterableUserDict
|
||||||
|
|
||||||
|
# We 'bundle' isclass instead of using inspect as importing inspect is
|
||||||
|
# fairly expensive (order of 10-15 ms for a modern machine in 2016)
|
||||||
|
def isclass(klass):
|
||||||
|
return isinstance(klass, (type, types.ClassType))
|
||||||
|
|
||||||
|
def new_class(name, bases, kwds, exec_body):
|
||||||
|
"""
|
||||||
|
A minimal stub of types.new_class that we need for make_class.
|
||||||
|
"""
|
||||||
|
ns = {}
|
||||||
|
exec_body(ns)
|
||||||
|
|
||||||
|
return type(name, bases, ns)
|
||||||
|
|
||||||
|
# TYPE is used in exceptions, repr(int) is different on Python 2 and 3.
|
||||||
|
TYPE = "type"
|
||||||
|
|
||||||
|
def iteritems(d):
|
||||||
|
return d.iteritems()
|
||||||
|
|
||||||
|
# Python 2 is bereft of a read-only dict proxy, so we make one!
|
||||||
|
class ReadOnlyDict(IterableUserDict):
|
||||||
|
"""
|
||||||
|
Best-effort read-only dict wrapper.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __setitem__(self, key, val):
|
||||||
|
# We gently pretend we're a Python 3 mappingproxy.
|
||||||
|
raise TypeError(
|
||||||
|
"'mappingproxy' object does not support item assignment"
|
||||||
|
)
|
||||||
|
|
||||||
|
def update(self, _):
|
||||||
|
# We gently pretend we're a Python 3 mappingproxy.
|
||||||
|
raise AttributeError(
|
||||||
|
"'mappingproxy' object has no attribute 'update'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __delitem__(self, _):
|
||||||
|
# We gently pretend we're a Python 3 mappingproxy.
|
||||||
|
raise TypeError(
|
||||||
|
"'mappingproxy' object does not support item deletion"
|
||||||
|
)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
# We gently pretend we're a Python 3 mappingproxy.
|
||||||
|
raise AttributeError(
|
||||||
|
"'mappingproxy' object has no attribute 'clear'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def pop(self, key, default=None):
|
||||||
|
# We gently pretend we're a Python 3 mappingproxy.
|
||||||
|
raise AttributeError(
|
||||||
|
"'mappingproxy' object has no attribute 'pop'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def popitem(self):
|
||||||
|
# We gently pretend we're a Python 3 mappingproxy.
|
||||||
|
raise AttributeError(
|
||||||
|
"'mappingproxy' object has no attribute 'popitem'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def setdefault(self, key, default=None):
|
||||||
|
# We gently pretend we're a Python 3 mappingproxy.
|
||||||
|
raise AttributeError(
|
||||||
|
"'mappingproxy' object has no attribute 'setdefault'"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
# Override to be identical to the Python 3 version.
|
||||||
|
return "mappingproxy(" + repr(self.data) + ")"
|
||||||
|
|
||||||
|
def metadata_proxy(d):
|
||||||
|
res = ReadOnlyDict()
|
||||||
|
res.data.update(d) # We blocked update, so we have to do it like this.
|
||||||
|
return res
|
||||||
|
|
||||||
|
def just_warn(*args, **kw): # pragma: no cover
|
||||||
|
"""
|
||||||
|
We only warn on Python 3 because we are not aware of any concrete
|
||||||
|
consequences of not setting the cell on Python 2.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
else: # Python 3 and later.
|
||||||
|
from collections.abc import Mapping, Sequence # noqa
|
||||||
|
|
||||||
|
def just_warn(*args, **kw):
|
||||||
|
"""
|
||||||
|
We only warn on Python 3 because we are not aware of any concrete
|
||||||
|
consequences of not setting the cell on Python 2.
|
||||||
|
"""
|
||||||
|
warnings.warn(
|
||||||
|
"Running interpreter doesn't sufficiently support code object "
|
||||||
|
"introspection. Some features like bare super() or accessing "
|
||||||
|
"__class__ will not work with slotted classes.",
|
||||||
|
RuntimeWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
def isclass(klass):
|
||||||
|
return isinstance(klass, type)
|
||||||
|
|
||||||
|
TYPE = "class"
|
||||||
|
|
||||||
|
def iteritems(d):
|
||||||
|
return d.items()
|
||||||
|
|
||||||
|
new_class = types.new_class
|
||||||
|
|
||||||
|
def metadata_proxy(d):
|
||||||
|
return types.MappingProxyType(dict(d))
|
||||||
|
|
||||||
|
|
||||||
|
def make_set_closure_cell():
|
||||||
|
"""Return a function of two arguments (cell, value) which sets
|
||||||
|
the value stored in the closure cell `cell` to `value`.
|
||||||
|
"""
|
||||||
|
# pypy makes this easy. (It also supports the logic below, but
|
||||||
|
# why not do the easy/fast thing?)
|
||||||
|
if PYPY:
|
||||||
|
|
||||||
|
def set_closure_cell(cell, value):
|
||||||
|
cell.__setstate__((value,))
|
||||||
|
|
||||||
|
return set_closure_cell
|
||||||
|
|
||||||
|
# Otherwise gotta do it the hard way.
|
||||||
|
|
||||||
|
# Create a function that will set its first cellvar to `value`.
|
||||||
|
def set_first_cellvar_to(value):
|
||||||
|
x = value
|
||||||
|
return
|
||||||
|
|
||||||
|
# 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()
|
23
lib/spack/external/attr/_config.py
vendored
Normal file
23
lib/spack/external/attr/_config.py
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["set_run_validators", "get_run_validators"]
|
||||||
|
|
||||||
|
_run_validators = True
|
||||||
|
|
||||||
|
|
||||||
|
def set_run_validators(run):
|
||||||
|
"""
|
||||||
|
Set whether or not validators are run. By default, they are run.
|
||||||
|
"""
|
||||||
|
if not isinstance(run, bool):
|
||||||
|
raise TypeError("'run' must be bool.")
|
||||||
|
global _run_validators
|
||||||
|
_run_validators = run
|
||||||
|
|
||||||
|
|
||||||
|
def get_run_validators():
|
||||||
|
"""
|
||||||
|
Return whether or not validators are run.
|
||||||
|
"""
|
||||||
|
return _run_validators
|
395
lib/spack/external/attr/_funcs.py
vendored
Normal file
395
lib/spack/external/attr/_funcs.py
vendored
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from ._compat import iteritems
|
||||||
|
from ._make import NOTHING, _obj_setattr, fields
|
||||||
|
from .exceptions import AttrsAttributeNotFoundError
|
||||||
|
|
||||||
|
|
||||||
|
def asdict(
|
||||||
|
inst,
|
||||||
|
recurse=True,
|
||||||
|
filter=None,
|
||||||
|
dict_factory=dict,
|
||||||
|
retain_collection_types=False,
|
||||||
|
value_serializer=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Return the ``attrs`` attribute values of *inst* as a dict.
|
||||||
|
|
||||||
|
Optionally recurse into other ``attrs``-decorated classes.
|
||||||
|
|
||||||
|
:param inst: Instance of an ``attrs``-decorated class.
|
||||||
|
:param bool recurse: Recurse into classes that are also
|
||||||
|
``attrs``-decorated.
|
||||||
|
:param callable filter: A callable whose return code determines whether an
|
||||||
|
attribute or element is included (``True``) or dropped (``False``). Is
|
||||||
|
called with the `attr.Attribute` as the first argument and the
|
||||||
|
value as the second argument.
|
||||||
|
:param callable dict_factory: A callable to produce dictionaries from. For
|
||||||
|
example, to produce ordered dictionaries instead of normal Python
|
||||||
|
dictionaries, pass in ``collections.OrderedDict``.
|
||||||
|
:param bool retain_collection_types: Do not convert to ``list`` when
|
||||||
|
encountering an attribute whose type is ``tuple`` or ``set``. Only
|
||||||
|
meaningful if ``recurse`` is ``True``.
|
||||||
|
:param Optional[callable] value_serializer: A hook that is called for every
|
||||||
|
attribute or dict key/value. It receives the current instance, field
|
||||||
|
and value and must return the (updated) value. The hook is run *after*
|
||||||
|
the optional *filter* has been applied.
|
||||||
|
|
||||||
|
:rtype: return type of *dict_factory*
|
||||||
|
|
||||||
|
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
|
||||||
|
class.
|
||||||
|
|
||||||
|
.. versionadded:: 16.0.0 *dict_factory*
|
||||||
|
.. versionadded:: 16.1.0 *retain_collection_types*
|
||||||
|
.. versionadded:: 20.3.0 *value_serializer*
|
||||||
|
"""
|
||||||
|
attrs = fields(inst.__class__)
|
||||||
|
rv = dict_factory()
|
||||||
|
for a in attrs:
|
||||||
|
v = getattr(inst, a.name)
|
||||||
|
if filter is not None and not filter(a, v):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if value_serializer is not None:
|
||||||
|
v = value_serializer(inst, a, v)
|
||||||
|
|
||||||
|
if recurse is True:
|
||||||
|
if has(v.__class__):
|
||||||
|
rv[a.name] = asdict(
|
||||||
|
v,
|
||||||
|
True,
|
||||||
|
filter,
|
||||||
|
dict_factory,
|
||||||
|
retain_collection_types,
|
||||||
|
value_serializer,
|
||||||
|
)
|
||||||
|
elif isinstance(v, (tuple, list, set, frozenset)):
|
||||||
|
cf = v.__class__ if retain_collection_types is True else list
|
||||||
|
rv[a.name] = cf(
|
||||||
|
[
|
||||||
|
_asdict_anything(
|
||||||
|
i,
|
||||||
|
filter,
|
||||||
|
dict_factory,
|
||||||
|
retain_collection_types,
|
||||||
|
value_serializer,
|
||||||
|
)
|
||||||
|
for i in v
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
df = dict_factory
|
||||||
|
rv[a.name] = df(
|
||||||
|
(
|
||||||
|
_asdict_anything(
|
||||||
|
kk,
|
||||||
|
filter,
|
||||||
|
df,
|
||||||
|
retain_collection_types,
|
||||||
|
value_serializer,
|
||||||
|
),
|
||||||
|
_asdict_anything(
|
||||||
|
vv,
|
||||||
|
filter,
|
||||||
|
df,
|
||||||
|
retain_collection_types,
|
||||||
|
value_serializer,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for kk, vv in iteritems(v)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
rv[a.name] = v
|
||||||
|
else:
|
||||||
|
rv[a.name] = v
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
def _asdict_anything(
|
||||||
|
val,
|
||||||
|
filter,
|
||||||
|
dict_factory,
|
||||||
|
retain_collection_types,
|
||||||
|
value_serializer,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
``asdict`` only works on attrs instances, this works on anything.
|
||||||
|
"""
|
||||||
|
if getattr(val.__class__, "__attrs_attrs__", None) is not None:
|
||||||
|
# Attrs class.
|
||||||
|
rv = asdict(
|
||||||
|
val,
|
||||||
|
True,
|
||||||
|
filter,
|
||||||
|
dict_factory,
|
||||||
|
retain_collection_types,
|
||||||
|
value_serializer,
|
||||||
|
)
|
||||||
|
elif isinstance(val, (tuple, list, set, frozenset)):
|
||||||
|
cf = val.__class__ if retain_collection_types is True else list
|
||||||
|
rv = cf(
|
||||||
|
[
|
||||||
|
_asdict_anything(
|
||||||
|
i,
|
||||||
|
filter,
|
||||||
|
dict_factory,
|
||||||
|
retain_collection_types,
|
||||||
|
value_serializer,
|
||||||
|
)
|
||||||
|
for i in val
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif isinstance(val, dict):
|
||||||
|
df = dict_factory
|
||||||
|
rv = df(
|
||||||
|
(
|
||||||
|
_asdict_anything(
|
||||||
|
kk, filter, df, retain_collection_types, value_serializer
|
||||||
|
),
|
||||||
|
_asdict_anything(
|
||||||
|
vv, filter, df, retain_collection_types, value_serializer
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for kk, vv in iteritems(val)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
rv = val
|
||||||
|
if value_serializer is not None:
|
||||||
|
rv = value_serializer(None, None, rv)
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
def astuple(
|
||||||
|
inst,
|
||||||
|
recurse=True,
|
||||||
|
filter=None,
|
||||||
|
tuple_factory=tuple,
|
||||||
|
retain_collection_types=False,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Return the ``attrs`` attribute values of *inst* as a tuple.
|
||||||
|
|
||||||
|
Optionally recurse into other ``attrs``-decorated classes.
|
||||||
|
|
||||||
|
:param inst: Instance of an ``attrs``-decorated class.
|
||||||
|
:param bool recurse: Recurse into classes that are also
|
||||||
|
``attrs``-decorated.
|
||||||
|
:param callable filter: A callable whose return code determines whether an
|
||||||
|
attribute or element is included (``True``) or dropped (``False``). Is
|
||||||
|
called with the `attr.Attribute` as the first argument and the
|
||||||
|
value as the second argument.
|
||||||
|
:param callable tuple_factory: A callable to produce tuples from. For
|
||||||
|
example, to produce lists instead of tuples.
|
||||||
|
:param bool retain_collection_types: Do not convert to ``list``
|
||||||
|
or ``dict`` when encountering an attribute which type is
|
||||||
|
``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is
|
||||||
|
``True``.
|
||||||
|
|
||||||
|
:rtype: return type of *tuple_factory*
|
||||||
|
|
||||||
|
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
|
||||||
|
class.
|
||||||
|
|
||||||
|
.. versionadded:: 16.2.0
|
||||||
|
"""
|
||||||
|
attrs = fields(inst.__class__)
|
||||||
|
rv = []
|
||||||
|
retain = retain_collection_types # Very long. :/
|
||||||
|
for a in attrs:
|
||||||
|
v = getattr(inst, a.name)
|
||||||
|
if filter is not None and not filter(a, v):
|
||||||
|
continue
|
||||||
|
if recurse is True:
|
||||||
|
if has(v.__class__):
|
||||||
|
rv.append(
|
||||||
|
astuple(
|
||||||
|
v,
|
||||||
|
recurse=True,
|
||||||
|
filter=filter,
|
||||||
|
tuple_factory=tuple_factory,
|
||||||
|
retain_collection_types=retain,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif isinstance(v, (tuple, list, set, frozenset)):
|
||||||
|
cf = v.__class__ if retain is True else list
|
||||||
|
rv.append(
|
||||||
|
cf(
|
||||||
|
[
|
||||||
|
astuple(
|
||||||
|
j,
|
||||||
|
recurse=True,
|
||||||
|
filter=filter,
|
||||||
|
tuple_factory=tuple_factory,
|
||||||
|
retain_collection_types=retain,
|
||||||
|
)
|
||||||
|
if has(j.__class__)
|
||||||
|
else j
|
||||||
|
for j in v
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
df = v.__class__ if retain is True else dict
|
||||||
|
rv.append(
|
||||||
|
df(
|
||||||
|
(
|
||||||
|
astuple(
|
||||||
|
kk,
|
||||||
|
tuple_factory=tuple_factory,
|
||||||
|
retain_collection_types=retain,
|
||||||
|
)
|
||||||
|
if has(kk.__class__)
|
||||||
|
else kk,
|
||||||
|
astuple(
|
||||||
|
vv,
|
||||||
|
tuple_factory=tuple_factory,
|
||||||
|
retain_collection_types=retain,
|
||||||
|
)
|
||||||
|
if has(vv.__class__)
|
||||||
|
else vv,
|
||||||
|
)
|
||||||
|
for kk, vv in iteritems(v)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
rv.append(v)
|
||||||
|
else:
|
||||||
|
rv.append(v)
|
||||||
|
|
||||||
|
return rv if tuple_factory is list else tuple_factory(rv)
|
||||||
|
|
||||||
|
|
||||||
|
def has(cls):
|
||||||
|
"""
|
||||||
|
Check whether *cls* is a class with ``attrs`` attributes.
|
||||||
|
|
||||||
|
:param type cls: Class to introspect.
|
||||||
|
:raise TypeError: If *cls* is not a class.
|
||||||
|
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
return getattr(cls, "__attrs_attrs__", None) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def assoc(inst, **changes):
|
||||||
|
"""
|
||||||
|
Copy *inst* and apply *changes*.
|
||||||
|
|
||||||
|
:param inst: Instance of a class with ``attrs`` attributes.
|
||||||
|
:param changes: Keyword changes in the new copy.
|
||||||
|
|
||||||
|
:return: A copy of inst with *changes* incorporated.
|
||||||
|
|
||||||
|
:raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't
|
||||||
|
be found on *cls*.
|
||||||
|
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
|
||||||
|
class.
|
||||||
|
|
||||||
|
.. deprecated:: 17.1.0
|
||||||
|
Use `evolve` instead.
|
||||||
|
"""
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"assoc is deprecated and will be removed after 2018/01.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
new = copy.copy(inst)
|
||||||
|
attrs = fields(inst.__class__)
|
||||||
|
for k, v in iteritems(changes):
|
||||||
|
a = getattr(attrs, k, NOTHING)
|
||||||
|
if a is NOTHING:
|
||||||
|
raise AttrsAttributeNotFoundError(
|
||||||
|
"{k} is not an attrs attribute on {cl}.".format(
|
||||||
|
k=k, cl=new.__class__
|
||||||
|
)
|
||||||
|
)
|
||||||
|
_obj_setattr(new, k, v)
|
||||||
|
return new
|
||||||
|
|
||||||
|
|
||||||
|
def evolve(inst, **changes):
|
||||||
|
"""
|
||||||
|
Create a new instance, based on *inst* with *changes* applied.
|
||||||
|
|
||||||
|
:param inst: Instance of a class with ``attrs`` attributes.
|
||||||
|
:param changes: Keyword changes in the new copy.
|
||||||
|
|
||||||
|
:return: A copy of inst with *changes* incorporated.
|
||||||
|
|
||||||
|
:raise TypeError: If *attr_name* couldn't be found in the class
|
||||||
|
``__init__``.
|
||||||
|
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
|
||||||
|
class.
|
||||||
|
|
||||||
|
.. versionadded:: 17.1.0
|
||||||
|
"""
|
||||||
|
cls = inst.__class__
|
||||||
|
attrs = fields(cls)
|
||||||
|
for a in attrs:
|
||||||
|
if not a.init:
|
||||||
|
continue
|
||||||
|
attr_name = a.name # To deal with private attributes.
|
||||||
|
init_name = attr_name if attr_name[0] != "_" else attr_name[1:]
|
||||||
|
if init_name not in changes:
|
||||||
|
changes[init_name] = getattr(inst, attr_name)
|
||||||
|
|
||||||
|
return cls(**changes)
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_types(cls, globalns=None, localns=None, attribs=None):
|
||||||
|
"""
|
||||||
|
Resolve any strings and forward annotations in type annotations.
|
||||||
|
|
||||||
|
This is only required if you need concrete types in `Attribute`'s *type*
|
||||||
|
field. In other words, you don't need to resolve your types if you only
|
||||||
|
use them for static type checking.
|
||||||
|
|
||||||
|
With no arguments, names will be looked up in the module in which the class
|
||||||
|
was created. If this is not what you want, e.g. if the name only exists
|
||||||
|
inside a method, you may pass *globalns* or *localns* to specify other
|
||||||
|
dictionaries in which to look up these names. See the docs of
|
||||||
|
`typing.get_type_hints` for more details.
|
||||||
|
|
||||||
|
:param type cls: Class to resolve.
|
||||||
|
:param Optional[dict] globalns: Dictionary containing global variables.
|
||||||
|
:param Optional[dict] localns: Dictionary containing local variables.
|
||||||
|
:param Optional[list] attribs: List of attribs for the given class.
|
||||||
|
This is necessary when calling from inside a ``field_transformer``
|
||||||
|
since *cls* is not an ``attrs`` class yet.
|
||||||
|
|
||||||
|
:raise TypeError: If *cls* is not a class.
|
||||||
|
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
|
||||||
|
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`.
|
||||||
|
|
||||||
|
.. 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:
|
||||||
|
import typing
|
||||||
|
|
||||||
|
hints = typing.get_type_hints(cls, globalns=globalns, localns=localns)
|
||||||
|
for field in fields(cls) if attribs is None else 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
|
||||||
|
|
||||||
|
# Return the class so you can use it as a decorator too.
|
||||||
|
return cls
|
3052
lib/spack/external/attr/_make.py
vendored
Normal file
3052
lib/spack/external/attr/_make.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
158
lib/spack/external/attr/_next_gen.py
vendored
Normal file
158
lib/spack/external/attr/_next_gen.py
vendored
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
from attr.exceptions import UnannotatedAttributeError
|
||||||
|
|
||||||
|
from . import setters
|
||||||
|
from ._make import NOTHING, _frozen_setattrs, attrib, attrs
|
||||||
|
|
||||||
|
|
||||||
|
def define(
|
||||||
|
maybe_cls=None,
|
||||||
|
*,
|
||||||
|
these=None,
|
||||||
|
repr=None,
|
||||||
|
hash=None,
|
||||||
|
init=None,
|
||||||
|
slots=True,
|
||||||
|
frozen=False,
|
||||||
|
weakref_slot=True,
|
||||||
|
str=False,
|
||||||
|
auto_attribs=None,
|
||||||
|
kw_only=False,
|
||||||
|
cache_hash=False,
|
||||||
|
auto_exc=True,
|
||||||
|
eq=None,
|
||||||
|
order=False,
|
||||||
|
auto_detect=True,
|
||||||
|
getstate_setstate=None,
|
||||||
|
on_setattr=None,
|
||||||
|
field_transformer=None,
|
||||||
|
):
|
||||||
|
r"""
|
||||||
|
The only behavioral differences are the handling of the *auto_attribs*
|
||||||
|
option:
|
||||||
|
|
||||||
|
: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
|
||||||
|
are found, it assumes *auto_attribs=True*.
|
||||||
|
2. Otherwise it assumes *auto_attribs=False* and tries to collect
|
||||||
|
`attr.ib`\ s.
|
||||||
|
|
||||||
|
and that mutable classes (``frozen=False``) validate on ``__setattr__``.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
def do_it(cls, auto_attribs):
|
||||||
|
return attrs(
|
||||||
|
maybe_cls=cls,
|
||||||
|
these=these,
|
||||||
|
repr=repr,
|
||||||
|
hash=hash,
|
||||||
|
init=init,
|
||||||
|
slots=slots,
|
||||||
|
frozen=frozen,
|
||||||
|
weakref_slot=weakref_slot,
|
||||||
|
str=str,
|
||||||
|
auto_attribs=auto_attribs,
|
||||||
|
kw_only=kw_only,
|
||||||
|
cache_hash=cache_hash,
|
||||||
|
auto_exc=auto_exc,
|
||||||
|
eq=eq,
|
||||||
|
order=order,
|
||||||
|
auto_detect=auto_detect,
|
||||||
|
collect_by_mro=True,
|
||||||
|
getstate_setstate=getstate_setstate,
|
||||||
|
on_setattr=on_setattr,
|
||||||
|
field_transformer=field_transformer,
|
||||||
|
)
|
||||||
|
|
||||||
|
def wrap(cls):
|
||||||
|
"""
|
||||||
|
Making this a wrapper ensures this code runs during class creation.
|
||||||
|
|
||||||
|
We also ensure that frozen-ness of classes is inherited.
|
||||||
|
"""
|
||||||
|
nonlocal frozen, on_setattr
|
||||||
|
|
||||||
|
had_on_setattr = on_setattr not in (None, setters.NO_OP)
|
||||||
|
|
||||||
|
# By default, mutable classes validate on setattr.
|
||||||
|
if frozen is False and on_setattr is None:
|
||||||
|
on_setattr = setters.validate
|
||||||
|
|
||||||
|
# However, if we subclass a frozen class, we inherit the immutability
|
||||||
|
# and disable on_setattr.
|
||||||
|
for base_cls in cls.__bases__:
|
||||||
|
if base_cls.__setattr__ is _frozen_setattrs:
|
||||||
|
if had_on_setattr:
|
||||||
|
raise ValueError(
|
||||||
|
"Frozen classes can't use on_setattr "
|
||||||
|
"(frozen-ness was inherited)."
|
||||||
|
)
|
||||||
|
|
||||||
|
on_setattr = setters.NO_OP
|
||||||
|
break
|
||||||
|
|
||||||
|
if auto_attribs is not None:
|
||||||
|
return do_it(cls, auto_attribs)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return do_it(cls, True)
|
||||||
|
except UnannotatedAttributeError:
|
||||||
|
return do_it(cls, False)
|
||||||
|
|
||||||
|
# maybe_cls's type depends on the usage of the decorator. It's a class
|
||||||
|
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
|
||||||
|
if maybe_cls is None:
|
||||||
|
return wrap
|
||||||
|
else:
|
||||||
|
return wrap(maybe_cls)
|
||||||
|
|
||||||
|
|
||||||
|
mutable = define
|
||||||
|
frozen = partial(define, frozen=True, on_setattr=None)
|
||||||
|
|
||||||
|
|
||||||
|
def field(
|
||||||
|
*,
|
||||||
|
default=NOTHING,
|
||||||
|
validator=None,
|
||||||
|
repr=True,
|
||||||
|
hash=None,
|
||||||
|
init=True,
|
||||||
|
metadata=None,
|
||||||
|
converter=None,
|
||||||
|
factory=None,
|
||||||
|
kw_only=False,
|
||||||
|
eq=None,
|
||||||
|
order=None,
|
||||||
|
on_setattr=None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Identical to `attr.ib`, except keyword-only and with some arguments
|
||||||
|
removed.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
return attrib(
|
||||||
|
default=default,
|
||||||
|
validator=validator,
|
||||||
|
repr=repr,
|
||||||
|
hash=hash,
|
||||||
|
init=init,
|
||||||
|
metadata=metadata,
|
||||||
|
converter=converter,
|
||||||
|
factory=factory,
|
||||||
|
kw_only=kw_only,
|
||||||
|
eq=eq,
|
||||||
|
order=order,
|
||||||
|
on_setattr=on_setattr,
|
||||||
|
)
|
85
lib/spack/external/attr/_version_info.py
vendored
Normal file
85
lib/spack/external/attr/_version_info.py
vendored
Normal 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
|
111
lib/spack/external/attr/converters.py
vendored
Normal file
111
lib/spack/external/attr/converters.py
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
"""
|
||||||
|
Commonly useful converters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from ._compat import PY2
|
||||||
|
from ._make import NOTHING, Factory, pipe
|
||||||
|
|
||||||
|
|
||||||
|
if not PY2:
|
||||||
|
import inspect
|
||||||
|
import typing
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"pipe",
|
||||||
|
"optional",
|
||||||
|
"default_if_none",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def optional(converter):
|
||||||
|
"""
|
||||||
|
A converter that allows an attribute to be optional. An optional attribute
|
||||||
|
is one which can be set to ``None``.
|
||||||
|
|
||||||
|
Type annotations will be inferred from the wrapped converter's, if it
|
||||||
|
has any.
|
||||||
|
|
||||||
|
:param callable converter: the converter that is used for non-``None``
|
||||||
|
values.
|
||||||
|
|
||||||
|
.. versionadded:: 17.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
def optional_converter(val):
|
||||||
|
if val is None:
|
||||||
|
return None
|
||||||
|
return converter(val)
|
||||||
|
|
||||||
|
if not PY2:
|
||||||
|
sig = None
|
||||||
|
try:
|
||||||
|
sig = inspect.signature(converter)
|
||||||
|
except (ValueError, TypeError): # inspect failed
|
||||||
|
pass
|
||||||
|
if sig:
|
||||||
|
params = list(sig.parameters.values())
|
||||||
|
if params and params[0].annotation is not inspect.Parameter.empty:
|
||||||
|
optional_converter.__annotations__["val"] = typing.Optional[
|
||||||
|
params[0].annotation
|
||||||
|
]
|
||||||
|
if sig.return_annotation is not inspect.Signature.empty:
|
||||||
|
optional_converter.__annotations__["return"] = typing.Optional[
|
||||||
|
sig.return_annotation
|
||||||
|
]
|
||||||
|
|
||||||
|
return optional_converter
|
||||||
|
|
||||||
|
|
||||||
|
def default_if_none(default=NOTHING, factory=None):
|
||||||
|
"""
|
||||||
|
A converter that allows to replace ``None`` values by *default* or the
|
||||||
|
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
|
||||||
|
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
|
||||||
|
``takes_self=True``.
|
||||||
|
|
||||||
|
.. versionadded:: 18.2.0
|
||||||
|
"""
|
||||||
|
if default is NOTHING and factory is None:
|
||||||
|
raise TypeError("Must pass either `default` or `factory`.")
|
||||||
|
|
||||||
|
if default is not NOTHING and factory is not None:
|
||||||
|
raise TypeError(
|
||||||
|
"Must pass either `default` or `factory` but not both."
|
||||||
|
)
|
||||||
|
|
||||||
|
if factory is not None:
|
||||||
|
default = Factory(factory)
|
||||||
|
|
||||||
|
if isinstance(default, Factory):
|
||||||
|
if default.takes_self:
|
||||||
|
raise ValueError(
|
||||||
|
"`takes_self` is not supported by default_if_none."
|
||||||
|
)
|
||||||
|
|
||||||
|
def default_if_none_converter(val):
|
||||||
|
if val is not None:
|
||||||
|
return val
|
||||||
|
|
||||||
|
return default.factory()
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
def default_if_none_converter(val):
|
||||||
|
if val is not None:
|
||||||
|
return val
|
||||||
|
|
||||||
|
return default
|
||||||
|
|
||||||
|
return default_if_none_converter
|
92
lib/spack/external/attr/exceptions.py
vendored
Normal file
92
lib/spack/external/attr/exceptions.py
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
|
||||||
|
class FrozenError(AttributeError):
|
||||||
|
"""
|
||||||
|
A frozen/immutable instance or attribute have been attempted to be
|
||||||
|
modified.
|
||||||
|
|
||||||
|
It mirrors the behavior of ``namedtuples`` by using the same error message
|
||||||
|
and subclassing `AttributeError`.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
msg = "can't set attribute"
|
||||||
|
args = [msg]
|
||||||
|
|
||||||
|
|
||||||
|
class FrozenInstanceError(FrozenError):
|
||||||
|
"""
|
||||||
|
A frozen instance has been attempted to be modified.
|
||||||
|
|
||||||
|
.. versionadded:: 16.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class FrozenAttributeError(FrozenError):
|
||||||
|
"""
|
||||||
|
A frozen attribute has been attempted to be modified.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class AttrsAttributeNotFoundError(ValueError):
|
||||||
|
"""
|
||||||
|
An ``attrs`` function couldn't find an attribute that the user asked for.
|
||||||
|
|
||||||
|
.. versionadded:: 16.2.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class NotAnAttrsClassError(ValueError):
|
||||||
|
"""
|
||||||
|
A non-``attrs`` class has been passed into an ``attrs`` function.
|
||||||
|
|
||||||
|
.. versionadded:: 16.2.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultAlreadySetError(RuntimeError):
|
||||||
|
"""
|
||||||
|
A default has been set using ``attr.ib()`` and is attempted to be reset
|
||||||
|
using the decorator.
|
||||||
|
|
||||||
|
.. versionadded:: 17.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class UnannotatedAttributeError(RuntimeError):
|
||||||
|
"""
|
||||||
|
A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type
|
||||||
|
annotation.
|
||||||
|
|
||||||
|
.. versionadded:: 17.3.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class PythonTooOldError(RuntimeError):
|
||||||
|
"""
|
||||||
|
It was attempted to use an ``attrs`` feature that requires a newer Python
|
||||||
|
version.
|
||||||
|
|
||||||
|
.. 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)
|
52
lib/spack/external/attr/filters.py
vendored
Normal file
52
lib/spack/external/attr/filters.py
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
"""
|
||||||
|
Commonly useful filters for `attr.asdict`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from ._compat import isclass
|
||||||
|
from ._make import Attribute
|
||||||
|
|
||||||
|
|
||||||
|
def _split_what(what):
|
||||||
|
"""
|
||||||
|
Returns a tuple of `frozenset`s of classes and attributes.
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
frozenset(cls for cls in what if isclass(cls)),
|
||||||
|
frozenset(cls for cls in what if isinstance(cls, Attribute)),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def include(*what):
|
||||||
|
"""
|
||||||
|
Whitelist *what*.
|
||||||
|
|
||||||
|
:param what: What to whitelist.
|
||||||
|
:type what: `list` of `type` or `attr.Attribute`\\ s
|
||||||
|
|
||||||
|
:rtype: `callable`
|
||||||
|
"""
|
||||||
|
cls, attrs = _split_what(what)
|
||||||
|
|
||||||
|
def include_(attribute, value):
|
||||||
|
return value.__class__ in cls or attribute in attrs
|
||||||
|
|
||||||
|
return include_
|
||||||
|
|
||||||
|
|
||||||
|
def exclude(*what):
|
||||||
|
"""
|
||||||
|
Blacklist *what*.
|
||||||
|
|
||||||
|
:param what: What to blacklist.
|
||||||
|
:type what: `list` of classes or `attr.Attribute`\\ s.
|
||||||
|
|
||||||
|
:rtype: `callable`
|
||||||
|
"""
|
||||||
|
cls, attrs = _split_what(what)
|
||||||
|
|
||||||
|
def exclude_(attribute, value):
|
||||||
|
return value.__class__ not in cls and attribute not in attrs
|
||||||
|
|
||||||
|
return exclude_
|
77
lib/spack/external/attr/setters.py
vendored
Normal file
77
lib/spack/external/attr/setters.py
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
"""
|
||||||
|
Commonly used hooks for on_setattr.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
from . import _config
|
||||||
|
from .exceptions import FrozenAttributeError
|
||||||
|
|
||||||
|
|
||||||
|
def pipe(*setters):
|
||||||
|
"""
|
||||||
|
Run all *setters* and return the return value of the last one.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapped_pipe(instance, attrib, new_value):
|
||||||
|
rv = new_value
|
||||||
|
|
||||||
|
for setter in setters:
|
||||||
|
rv = setter(instance, attrib, rv)
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
|
return wrapped_pipe
|
||||||
|
|
||||||
|
|
||||||
|
def frozen(_, __, ___):
|
||||||
|
"""
|
||||||
|
Prevent an attribute to be modified.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
raise FrozenAttributeError()
|
||||||
|
|
||||||
|
|
||||||
|
def validate(instance, attrib, new_value):
|
||||||
|
"""
|
||||||
|
Run *attrib*'s validator on *new_value* if it has one.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
if _config._run_validators is False:
|
||||||
|
return new_value
|
||||||
|
|
||||||
|
v = attrib.validator
|
||||||
|
if not v:
|
||||||
|
return new_value
|
||||||
|
|
||||||
|
v(instance, attrib, new_value)
|
||||||
|
|
||||||
|
return new_value
|
||||||
|
|
||||||
|
|
||||||
|
def convert(instance, attrib, new_value):
|
||||||
|
"""
|
||||||
|
Run *attrib*'s converter -- if it has one -- on *new_value* and return the
|
||||||
|
result.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
||||||
|
c = attrib.converter
|
||||||
|
if c:
|
||||||
|
return c(new_value)
|
||||||
|
|
||||||
|
return new_value
|
||||||
|
|
||||||
|
|
||||||
|
NO_OP = object()
|
||||||
|
"""
|
||||||
|
Sentinel for disabling class-wide *on_setattr* hooks for certain attributes.
|
||||||
|
|
||||||
|
Does not work in `pipe` or within lists.
|
||||||
|
|
||||||
|
.. versionadded:: 20.1.0
|
||||||
|
"""
|
379
lib/spack/external/attr/validators.py
vendored
Normal file
379
lib/spack/external/attr/validators.py
vendored
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
"""
|
||||||
|
Commonly useful validators.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ._make import _AndValidator, and_, attrib, attrs
|
||||||
|
from .exceptions import NotCallableError
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"and_",
|
||||||
|
"deep_iterable",
|
||||||
|
"deep_mapping",
|
||||||
|
"in_",
|
||||||
|
"instance_of",
|
||||||
|
"is_callable",
|
||||||
|
"matches_re",
|
||||||
|
"optional",
|
||||||
|
"provides",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@attrs(repr=False, slots=True, hash=True)
|
||||||
|
class _InstanceOfValidator(object):
|
||||||
|
type = attrib()
|
||||||
|
|
||||||
|
def __call__(self, inst, attr, value):
|
||||||
|
"""
|
||||||
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
|
"""
|
||||||
|
if not isinstance(value, self.type):
|
||||||
|
raise TypeError(
|
||||||
|
"'{name}' must be {type!r} (got {value!r} that is a "
|
||||||
|
"{actual!r}).".format(
|
||||||
|
name=attr.name,
|
||||||
|
type=self.type,
|
||||||
|
actual=value.__class__,
|
||||||
|
value=value,
|
||||||
|
),
|
||||||
|
attr,
|
||||||
|
self.type,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<instance_of validator for type {type!r}>".format(
|
||||||
|
type=self.type
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def instance_of(type):
|
||||||
|
"""
|
||||||
|
A validator that raises a `TypeError` if the initializer is called
|
||||||
|
with a wrong type for this particular attribute (checks are performed using
|
||||||
|
`isinstance` therefore it's also valid to pass a tuple of types).
|
||||||
|
|
||||||
|
:param type: The type to check for.
|
||||||
|
:type type: type or tuple of types
|
||||||
|
|
||||||
|
:raises TypeError: With a human readable error message, the attribute
|
||||||
|
(of type `attr.Attribute`), the expected type, and the value it
|
||||||
|
got.
|
||||||
|
"""
|
||||||
|
return _InstanceOfValidator(type)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs(repr=False, frozen=True, slots=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)
|
||||||
|
class _ProvidesValidator(object):
|
||||||
|
interface = attrib()
|
||||||
|
|
||||||
|
def __call__(self, inst, attr, value):
|
||||||
|
"""
|
||||||
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
|
"""
|
||||||
|
if not self.interface.providedBy(value):
|
||||||
|
raise TypeError(
|
||||||
|
"'{name}' must provide {interface!r} which {value!r} "
|
||||||
|
"doesn't.".format(
|
||||||
|
name=attr.name, interface=self.interface, value=value
|
||||||
|
),
|
||||||
|
attr,
|
||||||
|
self.interface,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<provides validator for interface {interface!r}>".format(
|
||||||
|
interface=self.interface
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def provides(interface):
|
||||||
|
"""
|
||||||
|
A validator that raises a `TypeError` if the initializer is called
|
||||||
|
with an object that does not provide the requested *interface* (checks are
|
||||||
|
performed using ``interface.providedBy(value)`` (see `zope.interface
|
||||||
|
<https://zopeinterface.readthedocs.io/en/latest/>`_).
|
||||||
|
|
||||||
|
:param interface: The interface to check for.
|
||||||
|
:type interface: ``zope.interface.Interface``
|
||||||
|
|
||||||
|
:raises TypeError: With a human readable error message, the attribute
|
||||||
|
(of type `attr.Attribute`), the expected interface, and the
|
||||||
|
value it got.
|
||||||
|
"""
|
||||||
|
return _ProvidesValidator(interface)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs(repr=False, slots=True, hash=True)
|
||||||
|
class _OptionalValidator(object):
|
||||||
|
validator = attrib()
|
||||||
|
|
||||||
|
def __call__(self, inst, attr, value):
|
||||||
|
if value is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.validator(inst, attr, value)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<optional validator for {what} or None>".format(
|
||||||
|
what=repr(self.validator)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def optional(validator):
|
||||||
|
"""
|
||||||
|
A validator that makes an attribute optional. An optional attribute is one
|
||||||
|
which can be set to ``None`` in addition to satisfying the requirements of
|
||||||
|
the sub-validator.
|
||||||
|
|
||||||
|
:param validator: A validator (or a list of validators) that is used for
|
||||||
|
non-``None`` values.
|
||||||
|
:type validator: callable or `list` of callables.
|
||||||
|
|
||||||
|
.. versionadded:: 15.1.0
|
||||||
|
.. versionchanged:: 17.1.0 *validator* can be a list of validators.
|
||||||
|
"""
|
||||||
|
if isinstance(validator, list):
|
||||||
|
return _OptionalValidator(_AndValidator(validator))
|
||||||
|
return _OptionalValidator(validator)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs(repr=False, slots=True, hash=True)
|
||||||
|
class _InValidator(object):
|
||||||
|
options = attrib()
|
||||||
|
|
||||||
|
def __call__(self, inst, attr, value):
|
||||||
|
try:
|
||||||
|
in_options = value in self.options
|
||||||
|
except TypeError: # e.g. `1 in "abc"`
|
||||||
|
in_options = False
|
||||||
|
|
||||||
|
if not in_options:
|
||||||
|
raise ValueError(
|
||||||
|
"'{name}' must be in {options!r} (got {value!r})".format(
|
||||||
|
name=attr.name, options=self.options, value=value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<in_ validator with options {options!r}>".format(
|
||||||
|
options=self.options
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def in_(options):
|
||||||
|
"""
|
||||||
|
A validator that raises a `ValueError` if the initializer is called
|
||||||
|
with a value that does not belong in the options provided. The check is
|
||||||
|
performed using ``value in options``.
|
||||||
|
|
||||||
|
:param options: Allowed options.
|
||||||
|
: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
|
||||||
|
got.
|
||||||
|
|
||||||
|
.. versionadded:: 17.1.0
|
||||||
|
"""
|
||||||
|
return _InValidator(options)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs(repr=False, slots=False, hash=True)
|
||||||
|
class _IsCallableValidator(object):
|
||||||
|
def __call__(self, inst, attr, value):
|
||||||
|
"""
|
||||||
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
|
"""
|
||||||
|
if not callable(value):
|
||||||
|
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):
|
||||||
|
return "<is_callable validator>"
|
||||||
|
|
||||||
|
|
||||||
|
def is_callable():
|
||||||
|
"""
|
||||||
|
A validator that raises a `attr.exceptions.NotCallableError` if the
|
||||||
|
initializer is called with a value for this particular attribute
|
||||||
|
that is not callable.
|
||||||
|
|
||||||
|
.. versionadded:: 19.1.0
|
||||||
|
|
||||||
|
:raises `attr.exceptions.NotCallableError`: With a human readable error
|
||||||
|
message containing the attribute (`attr.Attribute`) name,
|
||||||
|
and the value it got.
|
||||||
|
"""
|
||||||
|
return _IsCallableValidator()
|
||||||
|
|
||||||
|
|
||||||
|
@attrs(repr=False, slots=True, hash=True)
|
||||||
|
class _DeepIterable(object):
|
||||||
|
member_validator = attrib(validator=is_callable())
|
||||||
|
iterable_validator = attrib(
|
||||||
|
default=None, validator=optional(is_callable())
|
||||||
|
)
|
||||||
|
|
||||||
|
def __call__(self, inst, attr, value):
|
||||||
|
"""
|
||||||
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
|
"""
|
||||||
|
if self.iterable_validator is not None:
|
||||||
|
self.iterable_validator(inst, attr, value)
|
||||||
|
|
||||||
|
for member in value:
|
||||||
|
self.member_validator(inst, attr, member)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
iterable_identifier = (
|
||||||
|
""
|
||||||
|
if self.iterable_validator is None
|
||||||
|
else " {iterable!r}".format(iterable=self.iterable_validator)
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
"<deep_iterable validator for{iterable_identifier}"
|
||||||
|
" iterables of {member!r}>"
|
||||||
|
).format(
|
||||||
|
iterable_identifier=iterable_identifier,
|
||||||
|
member=self.member_validator,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def deep_iterable(member_validator, iterable_validator=None):
|
||||||
|
"""
|
||||||
|
A validator that performs deep validation of an iterable.
|
||||||
|
|
||||||
|
:param member_validator: Validator to apply to iterable members
|
||||||
|
:param iterable_validator: Validator to apply to iterable itself
|
||||||
|
(optional)
|
||||||
|
|
||||||
|
.. versionadded:: 19.1.0
|
||||||
|
|
||||||
|
:raises TypeError: if any sub-validators fail
|
||||||
|
"""
|
||||||
|
return _DeepIterable(member_validator, iterable_validator)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs(repr=False, slots=True, hash=True)
|
||||||
|
class _DeepMapping(object):
|
||||||
|
key_validator = attrib(validator=is_callable())
|
||||||
|
value_validator = attrib(validator=is_callable())
|
||||||
|
mapping_validator = attrib(default=None, validator=optional(is_callable()))
|
||||||
|
|
||||||
|
def __call__(self, inst, attr, value):
|
||||||
|
"""
|
||||||
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
|
"""
|
||||||
|
if self.mapping_validator is not None:
|
||||||
|
self.mapping_validator(inst, attr, value)
|
||||||
|
|
||||||
|
for key in value:
|
||||||
|
self.key_validator(inst, attr, key)
|
||||||
|
self.value_validator(inst, attr, value[key])
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return (
|
||||||
|
"<deep_mapping validator for objects mapping {key!r} to {value!r}>"
|
||||||
|
).format(key=self.key_validator, value=self.value_validator)
|
||||||
|
|
||||||
|
|
||||||
|
def deep_mapping(key_validator, value_validator, mapping_validator=None):
|
||||||
|
"""
|
||||||
|
A validator that performs deep validation of a dictionary.
|
||||||
|
|
||||||
|
:param key_validator: Validator to apply to dictionary keys
|
||||||
|
:param value_validator: Validator to apply to dictionary values
|
||||||
|
:param mapping_validator: Validator to apply to top-level mapping
|
||||||
|
attribute (optional)
|
||||||
|
|
||||||
|
.. versionadded:: 19.1.0
|
||||||
|
|
||||||
|
:raises TypeError: if any sub-validators fail
|
||||||
|
"""
|
||||||
|
return _DeepMapping(key_validator, value_validator, mapping_validator)
|
Loading…
Reference in New Issue
Block a user