mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-18 08:43:37 +00:00
Update attr 22.2.0 (683d056) → 23.1.0 (67e4ff2).
This commit is contained in:
parent
9962c1a112
commit
0b0c8827a2
14 changed files with 319 additions and 341 deletions
|
@ -1,5 +1,6 @@
|
||||||
### 3.31.0 (2023-1x-xx xx:xx:00 UTC)
|
### 3.31.0 (2023-1x-xx xx:xx:00 UTC)
|
||||||
|
|
||||||
|
* Update attr 22.2.0 (683d056) to 23.1.0 (67e4ff2)
|
||||||
* Update Beautiful Soup 4.12.2 to 4.12.2 (30c58a1)
|
* Update Beautiful Soup 4.12.2 to 4.12.2 (30c58a1)
|
||||||
* Update soupsieve 2.4.1 (2e66beb) to 2.5.0 (dc71495)
|
* Update soupsieve 2.4.1 (2e66beb) to 2.5.0 (dc71495)
|
||||||
* Update hachoir 3.1.2 (f739b43) to 3.2.0 (38d759f)
|
* Update hachoir 3.1.2 (f739b43) to 3.2.0 (38d759f)
|
||||||
|
|
|
@ -9,6 +9,7 @@ from typing import Callable
|
||||||
|
|
||||||
from . import converters, exceptions, filters, setters, validators
|
from . import converters, exceptions, filters, setters, validators
|
||||||
from ._cmp import cmp_using
|
from ._cmp import cmp_using
|
||||||
|
from ._compat import Protocol
|
||||||
from ._config import get_run_validators, set_run_validators
|
from ._config import get_run_validators, set_run_validators
|
||||||
from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
|
from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
|
||||||
from ._make import (
|
from ._make import (
|
||||||
|
@ -31,7 +32,7 @@ ib = attr = attrib
|
||||||
dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
|
dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
|
||||||
|
|
||||||
|
|
||||||
class AttrsInstance:
|
class AttrsInstance(Protocol):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,8 +91,9 @@ def _make_getattr(mod_name: str) -> Callable:
|
||||||
"__email__": "",
|
"__email__": "",
|
||||||
"__license__": "license",
|
"__license__": "license",
|
||||||
}
|
}
|
||||||
if name not in dunder_to_metadata.keys():
|
if name not in dunder_to_metadata:
|
||||||
raise AttributeError(f"module {mod_name} has no attribute {name}")
|
msg = f"module {mod_name} has no attribute {name}"
|
||||||
|
raise AttributeError(msg)
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
@ -101,7 +103,7 @@ def _make_getattr(mod_name: str) -> Callable:
|
||||||
else:
|
else:
|
||||||
from importlib.metadata import metadata
|
from importlib.metadata import metadata
|
||||||
|
|
||||||
if name != "__version_info__":
|
if name not in ("__version__", "__version_info__"):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
f"Accessing {mod_name}.{name} is deprecated and will be "
|
f"Accessing {mod_name}.{name} is deprecated and will be "
|
||||||
"removed in a future release. Use importlib.metadata directly "
|
"removed in a future release. Use importlib.metadata directly "
|
||||||
|
@ -113,15 +115,15 @@ def _make_getattr(mod_name: str) -> Callable:
|
||||||
meta = metadata("attrs")
|
meta = metadata("attrs")
|
||||||
if name == "__license__":
|
if name == "__license__":
|
||||||
return "MIT"
|
return "MIT"
|
||||||
elif name == "__copyright__":
|
if name == "__copyright__":
|
||||||
return "Copyright (c) 2015 Hynek Schlawack"
|
return "Copyright (c) 2015 Hynek Schlawack"
|
||||||
elif name in ("__uri__", "__url__"):
|
if name in ("__uri__", "__url__"):
|
||||||
return meta["Project-URL"].split(" ", 1)[-1]
|
return meta["Project-URL"].split(" ", 1)[-1]
|
||||||
elif name == "__version_info__":
|
if name == "__version_info__":
|
||||||
return VersionInfo._from_version_string(meta["version"])
|
return VersionInfo._from_version_string(meta["version"])
|
||||||
elif name == "__author__":
|
if name == "__author__":
|
||||||
return meta["Author-email"].rsplit(" ", 1)[0]
|
return meta["Author-email"].rsplit(" ", 1)[0]
|
||||||
elif name == "__email__":
|
if name == "__email__":
|
||||||
return meta["Author-email"].rsplit("<", 1)[1][:-1]
|
return meta["Author-email"].rsplit("<", 1)[1][:-1]
|
||||||
|
|
||||||
return meta[dunder_to_metadata[name]]
|
return meta[dunder_to_metadata[name]]
|
||||||
|
|
|
@ -33,6 +33,11 @@ if sys.version_info >= (3, 10):
|
||||||
else:
|
else:
|
||||||
from typing_extensions import TypeGuard
|
from typing_extensions import TypeGuard
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
from typing import dataclass_transform
|
||||||
|
else:
|
||||||
|
from typing_extensions import dataclass_transform
|
||||||
|
|
||||||
__version__: str
|
__version__: str
|
||||||
__version_info__: VersionInfo
|
__version_info__: VersionInfo
|
||||||
__title__: str
|
__title__: str
|
||||||
|
@ -69,8 +74,7 @@ _ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]]
|
||||||
class AttrsInstance(AttrsInstance_, Protocol):
|
class AttrsInstance(AttrsInstance_, Protocol):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_A = TypeVar("_A", bound=AttrsInstance)
|
_A = TypeVar("_A", bound=type[AttrsInstance])
|
||||||
# _make --
|
|
||||||
|
|
||||||
class _Nothing(enum.Enum):
|
class _Nothing(enum.Enum):
|
||||||
NOTHING = enum.auto()
|
NOTHING = enum.auto()
|
||||||
|
@ -104,23 +108,6 @@ else:
|
||||||
takes_self: bool = ...,
|
takes_self: bool = ...,
|
||||||
) -> _T: ...
|
) -> _T: ...
|
||||||
|
|
||||||
# Static type inference support via __dataclass_transform__ implemented as per:
|
|
||||||
# https://github.com/microsoft/pyright/blob/1.1.135/specs/dataclass_transforms.md
|
|
||||||
# This annotation must be applied to all overloads of "define" and "attrs"
|
|
||||||
#
|
|
||||||
# NOTE: This is a typing construct and does not exist at runtime. Extensions
|
|
||||||
# wrapping attrs decorators should declare a separate __dataclass_transform__
|
|
||||||
# signature in the extension module using the specification linked above to
|
|
||||||
# provide pyright support.
|
|
||||||
def __dataclass_transform__(
|
|
||||||
*,
|
|
||||||
eq_default: bool = True,
|
|
||||||
order_default: bool = False,
|
|
||||||
kw_only_default: bool = False,
|
|
||||||
frozen_default: bool = False,
|
|
||||||
field_descriptors: Tuple[Union[type, Callable[..., Any]], ...] = (()),
|
|
||||||
) -> Callable[[_T], _T]: ...
|
|
||||||
|
|
||||||
class Attribute(Generic[_T]):
|
class Attribute(Generic[_T]):
|
||||||
name: str
|
name: str
|
||||||
default: Optional[_T]
|
default: Optional[_T]
|
||||||
|
@ -323,7 +310,7 @@ def field(
|
||||||
type: Optional[type] = ...,
|
type: Optional[type] = ...,
|
||||||
) -> Any: ...
|
) -> Any: ...
|
||||||
@overload
|
@overload
|
||||||
@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field))
|
@dataclass_transform(order_default=True, field_specifiers=(attrib, field))
|
||||||
def attrs(
|
def attrs(
|
||||||
maybe_cls: _C,
|
maybe_cls: _C,
|
||||||
these: Optional[Dict[str, Any]] = ...,
|
these: Optional[Dict[str, Any]] = ...,
|
||||||
|
@ -351,7 +338,7 @@ def attrs(
|
||||||
unsafe_hash: Optional[bool] = ...,
|
unsafe_hash: Optional[bool] = ...,
|
||||||
) -> _C: ...
|
) -> _C: ...
|
||||||
@overload
|
@overload
|
||||||
@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field))
|
@dataclass_transform(order_default=True, field_specifiers=(attrib, field))
|
||||||
def attrs(
|
def attrs(
|
||||||
maybe_cls: None = ...,
|
maybe_cls: None = ...,
|
||||||
these: Optional[Dict[str, Any]] = ...,
|
these: Optional[Dict[str, Any]] = ...,
|
||||||
|
@ -379,7 +366,7 @@ def attrs(
|
||||||
unsafe_hash: Optional[bool] = ...,
|
unsafe_hash: Optional[bool] = ...,
|
||||||
) -> Callable[[_C], _C]: ...
|
) -> Callable[[_C], _C]: ...
|
||||||
@overload
|
@overload
|
||||||
@__dataclass_transform__(field_descriptors=(attrib, field))
|
@dataclass_transform(field_specifiers=(attrib, field))
|
||||||
def define(
|
def define(
|
||||||
maybe_cls: _C,
|
maybe_cls: _C,
|
||||||
*,
|
*,
|
||||||
|
@ -405,7 +392,7 @@ def define(
|
||||||
match_args: bool = ...,
|
match_args: bool = ...,
|
||||||
) -> _C: ...
|
) -> _C: ...
|
||||||
@overload
|
@overload
|
||||||
@__dataclass_transform__(field_descriptors=(attrib, field))
|
@dataclass_transform(field_specifiers=(attrib, field))
|
||||||
def define(
|
def define(
|
||||||
maybe_cls: None = ...,
|
maybe_cls: None = ...,
|
||||||
*,
|
*,
|
||||||
|
@ -434,9 +421,7 @@ def define(
|
||||||
mutable = define
|
mutable = define
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@__dataclass_transform__(
|
@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field))
|
||||||
frozen_default=True, field_descriptors=(attrib, field)
|
|
||||||
)
|
|
||||||
def frozen(
|
def frozen(
|
||||||
maybe_cls: _C,
|
maybe_cls: _C,
|
||||||
*,
|
*,
|
||||||
|
@ -462,9 +447,7 @@ def frozen(
|
||||||
match_args: bool = ...,
|
match_args: bool = ...,
|
||||||
) -> _C: ...
|
) -> _C: ...
|
||||||
@overload
|
@overload
|
||||||
@__dataclass_transform__(
|
@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field))
|
||||||
frozen_default=True, field_descriptors=(attrib, field)
|
|
||||||
)
|
|
||||||
def frozen(
|
def frozen(
|
||||||
maybe_cls: None = ...,
|
maybe_cls: None = ...,
|
||||||
*,
|
*,
|
||||||
|
|
|
@ -92,10 +92,8 @@ def cmp_using(
|
||||||
if not has_eq_function:
|
if not has_eq_function:
|
||||||
# functools.total_ordering requires __eq__ to be defined,
|
# functools.total_ordering requires __eq__ to be defined,
|
||||||
# so raise early error here to keep a nice stack.
|
# so raise early error here to keep a nice stack.
|
||||||
raise ValueError(
|
msg = "eq must be define is order to complete ordering from lt, le, gt, ge."
|
||||||
"eq must be define is order to complete ordering from "
|
raise ValueError(msg)
|
||||||
"lt, le, gt, ge."
|
|
||||||
)
|
|
||||||
type_ = functools.total_ordering(type_)
|
type_ = functools.total_ordering(type_)
|
||||||
|
|
||||||
return type_
|
return type_
|
||||||
|
@ -142,10 +140,7 @@ def _is_comparable_to(self, other):
|
||||||
"""
|
"""
|
||||||
Check whether `other` is comparable to `self`.
|
Check whether `other` is comparable to `self`.
|
||||||
"""
|
"""
|
||||||
for func in self._requirements:
|
return all(func(self, other) for func in self._requirements)
|
||||||
if not func(self, other):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def _check_same_type(self, other):
|
def _check_same_type(self, other):
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
@ -8,7 +7,7 @@ import threading
|
||||||
import types
|
import types
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from collections.abc import Mapping, Sequence # noqa
|
from collections.abc import Mapping, Sequence # noqa: F401
|
||||||
from typing import _GenericAlias
|
from typing import _GenericAlias
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +17,15 @@ PY310 = sys.version_info[:2] >= (3, 10)
|
||||||
PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
|
PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info < (3, 8):
|
||||||
|
try:
|
||||||
|
from typing_extensions import Protocol
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
Protocol = object
|
||||||
|
else:
|
||||||
|
from typing import Protocol # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
def just_warn(*args, **kw):
|
def just_warn(*args, **kw):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Running interpreter doesn't sufficiently support code object "
|
"Running interpreter doesn't sufficiently support code object "
|
||||||
|
@ -155,7 +163,7 @@ def make_set_closure_cell():
|
||||||
if cell.cell_contents != 100:
|
if cell.cell_contents != 100:
|
||||||
raise AssertionError # pragma: no cover
|
raise AssertionError # pragma: no cover
|
||||||
|
|
||||||
except Exception:
|
except Exception: # noqa: BLE001
|
||||||
return just_warn
|
return just_warn
|
||||||
else:
|
else:
|
||||||
return set_closure_cell
|
return set_closure_cell
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["set_run_validators", "get_run_validators"]
|
__all__ = ["set_run_validators", "get_run_validators"]
|
||||||
|
|
||||||
_run_validators = True
|
_run_validators = True
|
||||||
|
@ -15,7 +14,8 @@ def set_run_validators(run):
|
||||||
instead.
|
instead.
|
||||||
"""
|
"""
|
||||||
if not isinstance(run, bool):
|
if not isinstance(run, bool):
|
||||||
raise TypeError("'run' must be bool.")
|
msg = "'run' must be bool."
|
||||||
|
raise TypeError(msg)
|
||||||
global _run_validators
|
global _run_validators
|
||||||
_run_validators = run
|
_run_validators = run
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,7 @@ def asdict(
|
||||||
)
|
)
|
||||||
elif isinstance(v, (tuple, list, set, frozenset)):
|
elif isinstance(v, (tuple, list, set, frozenset)):
|
||||||
cf = v.__class__ if retain_collection_types is True else list
|
cf = v.__class__ if retain_collection_types is True else list
|
||||||
rv[a.name] = cf(
|
items = [
|
||||||
[
|
|
||||||
_asdict_anything(
|
_asdict_anything(
|
||||||
i,
|
i,
|
||||||
is_key=False,
|
is_key=False,
|
||||||
|
@ -84,7 +83,14 @@ def asdict(
|
||||||
)
|
)
|
||||||
for i in v
|
for i in v
|
||||||
]
|
]
|
||||||
)
|
try:
|
||||||
|
rv[a.name] = cf(items)
|
||||||
|
except TypeError:
|
||||||
|
if not issubclass(cf, tuple):
|
||||||
|
raise
|
||||||
|
# Workaround for TypeError: cf.__new__() missing 1 required
|
||||||
|
# positional argument (which appears, for a namedturle)
|
||||||
|
rv[a.name] = cf(*items)
|
||||||
elif isinstance(v, dict):
|
elif isinstance(v, dict):
|
||||||
df = dict_factory
|
df = dict_factory
|
||||||
rv[a.name] = df(
|
rv[a.name] = df(
|
||||||
|
@ -241,9 +247,7 @@ def astuple(
|
||||||
)
|
)
|
||||||
elif isinstance(v, (tuple, list, set, frozenset)):
|
elif isinstance(v, (tuple, list, set, frozenset)):
|
||||||
cf = v.__class__ if retain is True else list
|
cf = v.__class__ if retain is True else list
|
||||||
rv.append(
|
items = [
|
||||||
cf(
|
|
||||||
[
|
|
||||||
astuple(
|
astuple(
|
||||||
j,
|
j,
|
||||||
recurse=True,
|
recurse=True,
|
||||||
|
@ -255,8 +259,14 @@ def astuple(
|
||||||
else j
|
else j
|
||||||
for j in v
|
for j in v
|
||||||
]
|
]
|
||||||
)
|
try:
|
||||||
)
|
rv.append(cf(items))
|
||||||
|
except TypeError:
|
||||||
|
if not issubclass(cf, tuple):
|
||||||
|
raise
|
||||||
|
# Workaround for TypeError: cf.__new__() missing 1 required
|
||||||
|
# positional argument (which appears, for a namedturle)
|
||||||
|
rv.append(cf(*items))
|
||||||
elif isinstance(v, dict):
|
elif isinstance(v, dict):
|
||||||
df = v.__class__ if retain is True else dict
|
df = v.__class__ if retain is True else dict
|
||||||
rv.append(
|
rv.append(
|
||||||
|
@ -344,9 +354,8 @@ def assoc(inst, **changes):
|
||||||
for k, v in changes.items():
|
for k, v in changes.items():
|
||||||
a = getattr(attrs, k, NOTHING)
|
a = getattr(attrs, k, NOTHING)
|
||||||
if a is NOTHING:
|
if a is NOTHING:
|
||||||
raise AttrsAttributeNotFoundError(
|
msg = f"{k} is not an attrs attribute on {new.__class__}."
|
||||||
f"{k} is not an attrs attribute on {new.__class__}."
|
raise AttrsAttributeNotFoundError(msg)
|
||||||
)
|
|
||||||
_obj_setattr(new, k, v)
|
_obj_setattr(new, k, v)
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
@ -379,17 +388,14 @@ def evolve(*args, **changes):
|
||||||
try:
|
try:
|
||||||
(inst,) = args
|
(inst,) = args
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise TypeError(
|
msg = f"evolve() takes 1 positional argument, but {len(args)} were given"
|
||||||
f"evolve() takes 1 positional argument, but {len(args)} "
|
raise TypeError(msg) from None
|
||||||
"were given"
|
|
||||||
) from None
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
inst = changes.pop("inst")
|
inst = changes.pop("inst")
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise TypeError(
|
msg = "evolve() missing 1 required positional argument: 'inst'"
|
||||||
"evolve() missing 1 required positional argument: 'inst'"
|
raise TypeError(msg) from None
|
||||||
) from None
|
|
||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import copy
|
import copy
|
||||||
import enum
|
import enum
|
||||||
|
import inspect
|
||||||
import linecache
|
import linecache
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
@ -87,7 +89,7 @@ class _CacheHashWrapper(int):
|
||||||
See GH #613 for more details.
|
See GH #613 for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __reduce__(self, _none_constructor=type(None), _args=()):
|
def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008
|
||||||
return _none_constructor, _args
|
return _none_constructor, _args
|
||||||
|
|
||||||
|
|
||||||
|
@ -248,18 +250,18 @@ def attrib(
|
||||||
)
|
)
|
||||||
|
|
||||||
if hash is not None and hash is not True and hash is not False:
|
if hash is not None and hash is not True and hash is not False:
|
||||||
raise TypeError(
|
msg = "Invalid value for hash. Must be True, False, or None."
|
||||||
"Invalid value for hash. Must be True, False, or None."
|
raise TypeError(msg)
|
||||||
)
|
|
||||||
|
|
||||||
if factory is not None:
|
if factory is not None:
|
||||||
if default is not NOTHING:
|
if default is not NOTHING:
|
||||||
raise ValueError(
|
msg = (
|
||||||
"The `default` and `factory` arguments are mutually "
|
"The `default` and `factory` arguments are mutually exclusive."
|
||||||
"exclusive."
|
|
||||||
)
|
)
|
||||||
|
raise ValueError(msg)
|
||||||
if not callable(factory):
|
if not callable(factory):
|
||||||
raise ValueError("The `factory` argument must be a callable.")
|
msg = "The `factory` argument must be a callable."
|
||||||
|
raise ValueError(msg)
|
||||||
default = Factory(factory)
|
default = Factory(factory)
|
||||||
|
|
||||||
if metadata is None:
|
if metadata is None:
|
||||||
|
@ -323,7 +325,7 @@ def _make_method(name, script, filename, globs):
|
||||||
old_val = linecache.cache.setdefault(filename, linecache_tuple)
|
old_val = linecache.cache.setdefault(filename, linecache_tuple)
|
||||||
if old_val == linecache_tuple:
|
if old_val == linecache_tuple:
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
filename = f"{base_filename[:-1]}-{count}>"
|
filename = f"{base_filename[:-1]}-{count}>"
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
|
@ -430,7 +432,7 @@ def _collect_base_attrs(cls, taken_attr_names):
|
||||||
if a.inherited or a.name in taken_attr_names:
|
if a.inherited or a.name in taken_attr_names:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
a = a.evolve(inherited=True)
|
a = a.evolve(inherited=True) # noqa: PLW2901
|
||||||
base_attrs.append(a)
|
base_attrs.append(a)
|
||||||
base_attr_map[a.name] = base_cls
|
base_attr_map[a.name] = base_cls
|
||||||
|
|
||||||
|
@ -468,7 +470,7 @@ def _collect_base_attrs_broken(cls, taken_attr_names):
|
||||||
if a.name in taken_attr_names:
|
if a.name in taken_attr_names:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
a = a.evolve(inherited=True)
|
a = a.evolve(inherited=True) # noqa: PLW2901
|
||||||
taken_attr_names.add(a.name)
|
taken_attr_names.add(a.name)
|
||||||
base_attrs.append(a)
|
base_attrs.append(a)
|
||||||
base_attr_map[a.name] = base_cls
|
base_attr_map[a.name] = base_cls
|
||||||
|
@ -493,7 +495,7 @@ def _transform_attrs(
|
||||||
anns = _get_annotations(cls)
|
anns = _get_annotations(cls)
|
||||||
|
|
||||||
if these is not None:
|
if these is not None:
|
||||||
ca_list = [(name, ca) for name, ca in these.items()]
|
ca_list = list(these.items())
|
||||||
elif auto_attribs is True:
|
elif auto_attribs is True:
|
||||||
ca_names = {
|
ca_names = {
|
||||||
name
|
name
|
||||||
|
@ -509,10 +511,7 @@ def _transform_attrs(
|
||||||
a = cd.get(attr_name, NOTHING)
|
a = cd.get(attr_name, NOTHING)
|
||||||
|
|
||||||
if not isinstance(a, _CountingAttr):
|
if not isinstance(a, _CountingAttr):
|
||||||
if a is NOTHING:
|
a = attrib() if a is NOTHING else attrib(default=a)
|
||||||
a = attrib()
|
|
||||||
else:
|
|
||||||
a = attrib(default=a)
|
|
||||||
ca_list.append((attr_name, a))
|
ca_list.append((attr_name, a))
|
||||||
|
|
||||||
unannotated = ca_names - annot_names
|
unannotated = ca_names - annot_names
|
||||||
|
@ -563,10 +562,8 @@ def _transform_attrs(
|
||||||
had_default = False
|
had_default = False
|
||||||
for a in (a for a in attrs if a.init is not False and a.kw_only is False):
|
for a in (a for a in attrs if a.init is not False and a.kw_only is False):
|
||||||
if had_default is True and a.default is NOTHING:
|
if had_default is True and a.default is NOTHING:
|
||||||
raise ValueError(
|
msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}"
|
||||||
"No mandatory attributes allowed after an attribute with a "
|
raise ValueError(msg)
|
||||||
f"default value or factory. Attribute in question: {a!r}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if had_default is False and a.default is not NOTHING:
|
if had_default is False and a.default is not NOTHING:
|
||||||
had_default = True
|
had_default = True
|
||||||
|
@ -628,6 +625,7 @@ class _ClassBuilder:
|
||||||
"_delete_attribs",
|
"_delete_attribs",
|
||||||
"_frozen",
|
"_frozen",
|
||||||
"_has_pre_init",
|
"_has_pre_init",
|
||||||
|
"_pre_init_has_args",
|
||||||
"_has_post_init",
|
"_has_post_init",
|
||||||
"_is_exc",
|
"_is_exc",
|
||||||
"_on_setattr",
|
"_on_setattr",
|
||||||
|
@ -674,6 +672,13 @@ class _ClassBuilder:
|
||||||
self._weakref_slot = weakref_slot
|
self._weakref_slot = weakref_slot
|
||||||
self._cache_hash = cache_hash
|
self._cache_hash = cache_hash
|
||||||
self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
|
self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
|
||||||
|
self._pre_init_has_args = False
|
||||||
|
if self._has_pre_init:
|
||||||
|
# Check if the pre init method has more arguments than just `self`
|
||||||
|
# We want to pass arguments if pre init expects arguments
|
||||||
|
pre_init_func = cls.__attrs_pre_init__
|
||||||
|
pre_init_signature = inspect.signature(pre_init_func)
|
||||||
|
self._pre_init_has_args = len(pre_init_signature.parameters) > 1
|
||||||
self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
|
self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
|
||||||
self._delete_attribs = not bool(these)
|
self._delete_attribs = not bool(these)
|
||||||
self._is_exc = is_exc
|
self._is_exc = is_exc
|
||||||
|
@ -768,13 +773,11 @@ class _ClassBuilder:
|
||||||
name not in base_names
|
name not in base_names
|
||||||
and getattr(cls, name, _sentinel) is not _sentinel
|
and getattr(cls, name, _sentinel) is not _sentinel
|
||||||
):
|
):
|
||||||
try:
|
# An AttributeError can happen if a base class defines a
|
||||||
delattr(cls, name)
|
# class variable and we want to set an attribute with the
|
||||||
except AttributeError:
|
|
||||||
# This can happen if a base class defines a class
|
|
||||||
# variable and we want to set an attribute with the
|
|
||||||
# same name by using only a type annotation.
|
# same name by using only a type annotation.
|
||||||
pass
|
with contextlib.suppress(AttributeError):
|
||||||
|
delattr(cls, name)
|
||||||
|
|
||||||
# Attach our dunder methods.
|
# Attach our dunder methods.
|
||||||
for name, value in self._cls_dict.items():
|
for name, value in self._cls_dict.items():
|
||||||
|
@ -799,7 +802,7 @@ class _ClassBuilder:
|
||||||
cd = {
|
cd = {
|
||||||
k: v
|
k: v
|
||||||
for k, v in self._cls_dict.items()
|
for k, v in self._cls_dict.items()
|
||||||
if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")
|
if k not in (*tuple(self._attr_names), "__dict__", "__weakref__")
|
||||||
}
|
}
|
||||||
|
|
||||||
# If our class doesn't have its own implementation of __setattr__
|
# If our class doesn't have its own implementation of __setattr__
|
||||||
|
@ -821,7 +824,7 @@ class _ClassBuilder:
|
||||||
|
|
||||||
# Traverse the MRO to collect existing slots
|
# Traverse the MRO to collect existing slots
|
||||||
# and check for an existing __weakref__.
|
# and check for an existing __weakref__.
|
||||||
existing_slots = dict()
|
existing_slots = {}
|
||||||
weakref_inherited = False
|
weakref_inherited = False
|
||||||
for base_cls in self._cls.__mro__[1:-1]:
|
for base_cls in self._cls.__mro__[1:-1]:
|
||||||
if base_cls.__dict__.get("__weakref__", None) is not None:
|
if base_cls.__dict__.get("__weakref__", None) is not None:
|
||||||
|
@ -890,7 +893,8 @@ class _ClassBuilder:
|
||||||
for cell in closure_cells:
|
for cell in closure_cells:
|
||||||
try:
|
try:
|
||||||
match = cell.cell_contents is self._cls
|
match = cell.cell_contents is self._cls
|
||||||
except ValueError: # ValueError: Cell is empty
|
except ValueError: # noqa: PERF203
|
||||||
|
# ValueError: Cell is empty
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if match:
|
if match:
|
||||||
|
@ -907,9 +911,8 @@ class _ClassBuilder:
|
||||||
def add_str(self):
|
def add_str(self):
|
||||||
repr = self._cls_dict.get("__repr__")
|
repr = self._cls_dict.get("__repr__")
|
||||||
if repr is None:
|
if repr is None:
|
||||||
raise ValueError(
|
msg = "__str__ can only be generated if a __repr__ exists."
|
||||||
"__str__ can only be generated if a __repr__ exists."
|
raise ValueError(msg)
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.__repr__()
|
return self.__repr__()
|
||||||
|
@ -980,6 +983,7 @@ class _ClassBuilder:
|
||||||
self._cls,
|
self._cls,
|
||||||
self._attrs,
|
self._attrs,
|
||||||
self._has_pre_init,
|
self._has_pre_init,
|
||||||
|
self._pre_init_has_args,
|
||||||
self._has_post_init,
|
self._has_post_init,
|
||||||
self._frozen,
|
self._frozen,
|
||||||
self._slots,
|
self._slots,
|
||||||
|
@ -1006,6 +1010,7 @@ class _ClassBuilder:
|
||||||
self._cls,
|
self._cls,
|
||||||
self._attrs,
|
self._attrs,
|
||||||
self._has_pre_init,
|
self._has_pre_init,
|
||||||
|
self._pre_init_has_args,
|
||||||
self._has_post_init,
|
self._has_post_init,
|
||||||
self._frozen,
|
self._frozen,
|
||||||
self._slots,
|
self._slots,
|
||||||
|
@ -1054,9 +1059,8 @@ class _ClassBuilder:
|
||||||
|
|
||||||
if self._has_custom_setattr:
|
if self._has_custom_setattr:
|
||||||
# We need to write a __setattr__ but there already is one!
|
# We need to write a __setattr__ but there already is one!
|
||||||
raise ValueError(
|
msg = "Can't combine custom __setattr__ with on_setattr hooks."
|
||||||
"Can't combine custom __setattr__ with on_setattr hooks."
|
raise ValueError(msg)
|
||||||
)
|
|
||||||
|
|
||||||
# docstring comes from _add_method_dunders
|
# docstring comes from _add_method_dunders
|
||||||
def __setattr__(self, name, val):
|
def __setattr__(self, name, val):
|
||||||
|
@ -1079,25 +1083,17 @@ class _ClassBuilder:
|
||||||
"""
|
"""
|
||||||
Add __module__ and __qualname__ to a *method* if possible.
|
Add __module__ and __qualname__ to a *method* if possible.
|
||||||
"""
|
"""
|
||||||
try:
|
with contextlib.suppress(AttributeError):
|
||||||
method.__module__ = self._cls.__module__
|
method.__module__ = self._cls.__module__
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
with contextlib.suppress(AttributeError):
|
||||||
method.__qualname__ = ".".join(
|
method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}"
|
||||||
(self._cls.__qualname__, method.__name__)
|
|
||||||
)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
with contextlib.suppress(AttributeError):
|
||||||
method.__doc__ = (
|
method.__doc__ = (
|
||||||
"Method generated by attrs for class "
|
"Method generated by attrs for class "
|
||||||
f"{self._cls.__qualname__}."
|
f"{self._cls.__qualname__}."
|
||||||
)
|
)
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return method
|
return method
|
||||||
|
|
||||||
|
@ -1108,7 +1104,8 @@ def _determine_attrs_eq_order(cmp, eq, order, default_eq):
|
||||||
values of eq and order. If *eq* is None, set it to *default_eq*.
|
values of eq and order. If *eq* is None, set it to *default_eq*.
|
||||||
"""
|
"""
|
||||||
if cmp is not None and any((eq is not None, order is not None)):
|
if cmp is not None and any((eq is not None, order is not None)):
|
||||||
raise ValueError("Don't mix `cmp` with `eq' and `order`.")
|
msg = "Don't mix `cmp` with `eq' and `order`."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
# cmp takes precedence due to bw-compatibility.
|
# cmp takes precedence due to bw-compatibility.
|
||||||
if cmp is not None:
|
if cmp is not None:
|
||||||
|
@ -1123,7 +1120,8 @@ def _determine_attrs_eq_order(cmp, eq, order, default_eq):
|
||||||
order = eq
|
order = eq
|
||||||
|
|
||||||
if eq is False and order is True:
|
if eq is False and order is True:
|
||||||
raise ValueError("`order` can only be True if `eq` is True too.")
|
msg = "`order` can only be True if `eq` is True too."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
return eq, order
|
return eq, order
|
||||||
|
|
||||||
|
@ -1134,7 +1132,8 @@ def _determine_attrib_eq_order(cmp, eq, order, default_eq):
|
||||||
values of eq and order. If *eq* is None, set it to *default_eq*.
|
values of eq and order. If *eq* is None, set it to *default_eq*.
|
||||||
"""
|
"""
|
||||||
if cmp is not None and any((eq is not None, order is not None)):
|
if cmp is not None and any((eq is not None, order is not None)):
|
||||||
raise ValueError("Don't mix `cmp` with `eq' and `order`.")
|
msg = "Don't mix `cmp` with `eq' and `order`."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
def decide_callable_or_boolean(value):
|
def decide_callable_or_boolean(value):
|
||||||
"""
|
"""
|
||||||
|
@ -1164,7 +1163,8 @@ def _determine_attrib_eq_order(cmp, eq, order, default_eq):
|
||||||
order, order_key = decide_callable_or_boolean(order)
|
order, order_key = decide_callable_or_boolean(order)
|
||||||
|
|
||||||
if eq is False and order is True:
|
if eq is False and order is True:
|
||||||
raise ValueError("`order` can only be True if `eq` is True too.")
|
msg = "`order` can only be True if `eq` is True too."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
return eq, eq_key, order, order_key
|
return eq, eq_key, order, order_key
|
||||||
|
|
||||||
|
@ -1494,7 +1494,8 @@ def attrs(
|
||||||
)
|
)
|
||||||
|
|
||||||
if has_own_setattr and is_frozen:
|
if has_own_setattr and is_frozen:
|
||||||
raise ValueError("Can't freeze a class with a custom __setattr__.")
|
msg = "Can't freeze a class with a custom __setattr__."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
builder = _ClassBuilder(
|
builder = _ClassBuilder(
|
||||||
cls,
|
cls,
|
||||||
|
@ -1547,18 +1548,15 @@ def attrs(
|
||||||
|
|
||||||
if hash is not True and hash is not False and hash is not None:
|
if hash is not True and hash is not False and hash is not None:
|
||||||
# Can't use `hash in` because 1 == True for example.
|
# Can't use `hash in` because 1 == True for example.
|
||||||
raise TypeError(
|
msg = "Invalid value for hash. Must be True, False, or None."
|
||||||
"Invalid value for hash. Must be True, False, or None."
|
raise TypeError(msg)
|
||||||
)
|
|
||||||
elif hash is False or (hash is None and eq is False) or is_exc:
|
if hash is False or (hash is None and eq is False) or is_exc:
|
||||||
# Don't do anything. Should fall back to __object__'s __hash__
|
# Don't do anything. Should fall back to __object__'s __hash__
|
||||||
# which is by id.
|
# which is by id.
|
||||||
if cache_hash:
|
if cache_hash:
|
||||||
raise TypeError(
|
msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled."
|
||||||
"Invalid value for cache_hash. To use hash caching,"
|
raise TypeError(msg)
|
||||||
" hashing must be either explicitly or implicitly "
|
|
||||||
"enabled."
|
|
||||||
)
|
|
||||||
elif hash is True or (
|
elif hash is True or (
|
||||||
hash is None and eq is True and is_frozen is True
|
hash is None and eq is True and is_frozen is True
|
||||||
):
|
):
|
||||||
|
@ -1567,11 +1565,8 @@ def attrs(
|
||||||
else:
|
else:
|
||||||
# Raise TypeError on attempts to hash.
|
# Raise TypeError on attempts to hash.
|
||||||
if cache_hash:
|
if cache_hash:
|
||||||
raise TypeError(
|
msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled."
|
||||||
"Invalid value for cache_hash. To use hash caching,"
|
raise TypeError(msg)
|
||||||
" hashing must be either explicitly or implicitly "
|
|
||||||
"enabled."
|
|
||||||
)
|
|
||||||
builder.make_unhashable()
|
builder.make_unhashable()
|
||||||
|
|
||||||
if _determine_whether_to_implement(
|
if _determine_whether_to_implement(
|
||||||
|
@ -1581,10 +1576,8 @@ def attrs(
|
||||||
else:
|
else:
|
||||||
builder.add_attrs_init()
|
builder.add_attrs_init()
|
||||||
if cache_hash:
|
if cache_hash:
|
||||||
raise TypeError(
|
msg = "Invalid value for cache_hash. To use hash caching, init must be True."
|
||||||
"Invalid value for cache_hash. To use hash caching,"
|
raise TypeError(msg)
|
||||||
" init must be True."
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
PY310
|
PY310
|
||||||
|
@ -1599,7 +1592,7 @@ def attrs(
|
||||||
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
|
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
|
||||||
if maybe_cls is None:
|
if maybe_cls is None:
|
||||||
return wrap
|
return wrap
|
||||||
else:
|
|
||||||
return wrap(maybe_cls)
|
return wrap(maybe_cls)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1648,10 +1641,7 @@ def _make_hash(cls, attrs, frozen, cache_hash):
|
||||||
else:
|
else:
|
||||||
hash_def += ", *"
|
hash_def += ", *"
|
||||||
|
|
||||||
hash_def += (
|
hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):"
|
||||||
", _cache_wrapper="
|
|
||||||
+ "__import__('attr._make')._make._CacheHashWrapper):"
|
|
||||||
)
|
|
||||||
hash_func = "_cache_wrapper(" + hash_func
|
hash_func = "_cache_wrapper(" + hash_func
|
||||||
closing_braces += ")"
|
closing_braces += ")"
|
||||||
|
|
||||||
|
@ -1760,7 +1750,7 @@ def _make_eq(cls, attrs):
|
||||||
lines.append(f" self.{a.name},")
|
lines.append(f" self.{a.name},")
|
||||||
others.append(f" other.{a.name},")
|
others.append(f" other.{a.name},")
|
||||||
|
|
||||||
lines += others + [" )"]
|
lines += [*others, " )"]
|
||||||
else:
|
else:
|
||||||
lines.append(" return True")
|
lines.append(" return True")
|
||||||
|
|
||||||
|
@ -1928,7 +1918,8 @@ def fields(cls):
|
||||||
generic_base = get_generic_base(cls)
|
generic_base = get_generic_base(cls)
|
||||||
|
|
||||||
if generic_base is None and not isinstance(cls, type):
|
if generic_base is None and not isinstance(cls, type):
|
||||||
raise TypeError("Passed object must be a class.")
|
msg = "Passed object must be a class."
|
||||||
|
raise TypeError(msg)
|
||||||
|
|
||||||
attrs = getattr(cls, "__attrs_attrs__", None)
|
attrs = getattr(cls, "__attrs_attrs__", None)
|
||||||
|
|
||||||
|
@ -1941,7 +1932,8 @@ def fields(cls):
|
||||||
# efficient.
|
# efficient.
|
||||||
cls.__attrs_attrs__ = attrs
|
cls.__attrs_attrs__ = attrs
|
||||||
return attrs
|
return attrs
|
||||||
raise NotAnAttrsClassError(f"{cls!r} is not an attrs-decorated class.")
|
msg = f"{cls!r} is not an attrs-decorated class."
|
||||||
|
raise NotAnAttrsClassError(msg)
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
@ -1962,10 +1954,12 @@ def fields_dict(cls):
|
||||||
.. versionadded:: 18.1.0
|
.. versionadded:: 18.1.0
|
||||||
"""
|
"""
|
||||||
if not isinstance(cls, type):
|
if not isinstance(cls, type):
|
||||||
raise TypeError("Passed object must be a class.")
|
msg = "Passed object must be a class."
|
||||||
|
raise TypeError(msg)
|
||||||
attrs = getattr(cls, "__attrs_attrs__", None)
|
attrs = getattr(cls, "__attrs_attrs__", None)
|
||||||
if attrs is None:
|
if attrs is None:
|
||||||
raise NotAnAttrsClassError(f"{cls!r} is not an attrs-decorated class.")
|
msg = f"{cls!r} is not an attrs-decorated class."
|
||||||
|
raise NotAnAttrsClassError(msg)
|
||||||
return {a.name: a for a in attrs}
|
return {a.name: a for a in attrs}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2001,6 +1995,7 @@ def _make_init(
|
||||||
cls,
|
cls,
|
||||||
attrs,
|
attrs,
|
||||||
pre_init,
|
pre_init,
|
||||||
|
pre_init_has_args,
|
||||||
post_init,
|
post_init,
|
||||||
frozen,
|
frozen,
|
||||||
slots,
|
slots,
|
||||||
|
@ -2015,7 +2010,8 @@ def _make_init(
|
||||||
)
|
)
|
||||||
|
|
||||||
if frozen and has_cls_on_setattr:
|
if frozen and has_cls_on_setattr:
|
||||||
raise ValueError("Frozen classes can't use on_setattr.")
|
msg = "Frozen classes can't use on_setattr."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
needs_cached_setattr = cache_hash or frozen
|
needs_cached_setattr = cache_hash or frozen
|
||||||
filtered_attrs = []
|
filtered_attrs = []
|
||||||
|
@ -2029,7 +2025,8 @@ def _make_init(
|
||||||
|
|
||||||
if a.on_setattr is not None:
|
if a.on_setattr is not None:
|
||||||
if frozen is True:
|
if frozen is True:
|
||||||
raise ValueError("Frozen classes can't use on_setattr.")
|
msg = "Frozen classes can't use on_setattr."
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
needs_cached_setattr = True
|
needs_cached_setattr = True
|
||||||
elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP:
|
elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP:
|
||||||
|
@ -2042,6 +2039,7 @@ def _make_init(
|
||||||
frozen,
|
frozen,
|
||||||
slots,
|
slots,
|
||||||
pre_init,
|
pre_init,
|
||||||
|
pre_init_has_args,
|
||||||
post_init,
|
post_init,
|
||||||
cache_hash,
|
cache_hash,
|
||||||
base_attr_map,
|
base_attr_map,
|
||||||
|
@ -2122,6 +2120,7 @@ def _attrs_to_init_script(
|
||||||
frozen,
|
frozen,
|
||||||
slots,
|
slots,
|
||||||
pre_init,
|
pre_init,
|
||||||
|
pre_init_has_args,
|
||||||
post_init,
|
post_init,
|
||||||
cache_hash,
|
cache_hash,
|
||||||
base_attr_map,
|
base_attr_map,
|
||||||
|
@ -2208,10 +2207,7 @@ def _attrs_to_init_script(
|
||||||
arg_name = a.alias
|
arg_name = a.alias
|
||||||
|
|
||||||
has_factory = isinstance(a.default, Factory)
|
has_factory = isinstance(a.default, Factory)
|
||||||
if has_factory and a.default.takes_self:
|
maybe_self = "self" if has_factory and a.default.takes_self else ""
|
||||||
maybe_self = "self"
|
|
||||||
else:
|
|
||||||
maybe_self = ""
|
|
||||||
|
|
||||||
if a.init is False:
|
if a.init is False:
|
||||||
if has_factory:
|
if has_factory:
|
||||||
|
@ -2235,8 +2231,7 @@ def _attrs_to_init_script(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
names_for_globals[init_factory_name] = a.default.factory
|
names_for_globals[init_factory_name] = a.default.factory
|
||||||
else:
|
elif a.converter is not None:
|
||||||
if a.converter is not None:
|
|
||||||
lines.append(
|
lines.append(
|
||||||
fmt_setter_with_converter(
|
fmt_setter_with_converter(
|
||||||
attr_name,
|
attr_name,
|
||||||
|
@ -2362,7 +2357,7 @@ def _attrs_to_init_script(
|
||||||
# hash code would result in silent bugs.
|
# hash code would result in silent bugs.
|
||||||
if cache_hash:
|
if cache_hash:
|
||||||
if frozen:
|
if frozen:
|
||||||
if slots:
|
if slots: # noqa: SIM108
|
||||||
# if frozen and slots, then _setattr defined above
|
# if frozen and slots, then _setattr defined above
|
||||||
init_hash_cache = "_setattr('%s', %s)"
|
init_hash_cache = "_setattr('%s', %s)"
|
||||||
else:
|
else:
|
||||||
|
@ -2380,11 +2375,23 @@ def _attrs_to_init_script(
|
||||||
lines.append(f"BaseException.__init__(self, {vals})")
|
lines.append(f"BaseException.__init__(self, {vals})")
|
||||||
|
|
||||||
args = ", ".join(args)
|
args = ", ".join(args)
|
||||||
|
pre_init_args = args
|
||||||
if kw_only_args:
|
if kw_only_args:
|
||||||
args += "%s*, %s" % (
|
args += "%s*, %s" % (
|
||||||
", " if args else "", # leading comma
|
", " if args else "", # leading comma
|
||||||
", ".join(kw_only_args), # kw_only args
|
", ".join(kw_only_args), # kw_only args
|
||||||
)
|
)
|
||||||
|
pre_init_kw_only_args = ", ".join(
|
||||||
|
["%s=%s" % (kw_arg, kw_arg) for kw_arg in kw_only_args]
|
||||||
|
)
|
||||||
|
pre_init_args += (
|
||||||
|
", " if pre_init_args else ""
|
||||||
|
) # handle only kwargs and no regular args
|
||||||
|
pre_init_args += pre_init_kw_only_args
|
||||||
|
|
||||||
|
if pre_init and pre_init_has_args:
|
||||||
|
# If pre init method has arguments, pass same arguments as `__init__`
|
||||||
|
lines[0] = "self.__attrs_pre_init__(%s)" % pre_init_args
|
||||||
|
|
||||||
return (
|
return (
|
||||||
"def %s(self, %s):\n %s\n"
|
"def %s(self, %s):\n %s\n"
|
||||||
|
@ -2537,9 +2544,8 @@ class Attribute:
|
||||||
if type is None:
|
if type is None:
|
||||||
type = ca.type
|
type = ca.type
|
||||||
elif ca.type is not None:
|
elif ca.type is not None:
|
||||||
raise ValueError(
|
msg = "Type annotation and type argument cannot both be present"
|
||||||
"Type annotation and type argument cannot both be present"
|
raise ValueError(msg)
|
||||||
)
|
|
||||||
inst_dict = {
|
inst_dict = {
|
||||||
k: getattr(ca, k)
|
k: getattr(ca, k)
|
||||||
for k in Attribute.__slots__
|
for k in Attribute.__slots__
|
||||||
|
@ -2663,7 +2669,8 @@ class _CountingAttr:
|
||||||
"on_setattr",
|
"on_setattr",
|
||||||
"alias",
|
"alias",
|
||||||
)
|
)
|
||||||
__attrs_attrs__ = tuple(
|
__attrs_attrs__ = (
|
||||||
|
*tuple(
|
||||||
Attribute(
|
Attribute(
|
||||||
name=name,
|
name=name,
|
||||||
alias=_default_init_alias_for(name),
|
alias=_default_init_alias_for(name),
|
||||||
|
@ -2692,7 +2699,7 @@ class _CountingAttr:
|
||||||
"on_setattr",
|
"on_setattr",
|
||||||
"alias",
|
"alias",
|
||||||
)
|
)
|
||||||
) + (
|
),
|
||||||
Attribute(
|
Attribute(
|
||||||
name="metadata",
|
name="metadata",
|
||||||
alias="metadata",
|
alias="metadata",
|
||||||
|
@ -2868,7 +2875,8 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
|
||||||
elif isinstance(attrs, (list, tuple)):
|
elif isinstance(attrs, (list, tuple)):
|
||||||
cls_dict = {a: attrib() for a in attrs}
|
cls_dict = {a: attrib() for a in attrs}
|
||||||
else:
|
else:
|
||||||
raise TypeError("attrs argument must be a dict or a list.")
|
msg = "attrs argument must be a dict or a list."
|
||||||
|
raise TypeError(msg)
|
||||||
|
|
||||||
pre_init = cls_dict.pop("__attrs_pre_init__", None)
|
pre_init = cls_dict.pop("__attrs_pre_init__", None)
|
||||||
post_init = cls_dict.pop("__attrs_post_init__", None)
|
post_init = cls_dict.pop("__attrs_post_init__", None)
|
||||||
|
@ -2888,12 +2896,10 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
|
||||||
# frame where the class is created. Bypass this step in environments where
|
# frame where the class is created. Bypass this step in environments where
|
||||||
# sys._getframe is not defined (Jython for example) or sys._getframe is not
|
# sys._getframe is not defined (Jython for example) or sys._getframe is not
|
||||||
# defined for arguments greater than 0 (IronPython).
|
# defined for arguments greater than 0 (IronPython).
|
||||||
try:
|
with contextlib.suppress(AttributeError, ValueError):
|
||||||
type_.__module__ = sys._getframe(1).f_globals.get(
|
type_.__module__ = sys._getframe(1).f_globals.get(
|
||||||
"__name__", "__main__"
|
"__name__", "__main__"
|
||||||
)
|
)
|
||||||
except (AttributeError, ValueError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# We do it here for proper warnings with meaningful stacklevel.
|
# We do it here for proper warnings with meaningful stacklevel.
|
||||||
cmp = attributes_arguments.pop("cmp", None)
|
cmp = attributes_arguments.pop("cmp", None)
|
||||||
|
|
|
@ -59,7 +59,7 @@ def define(
|
||||||
.. caution::
|
.. caution::
|
||||||
|
|
||||||
Usually this has only upsides and few visible effects in everyday
|
Usually this has only upsides and few visible effects in everyday
|
||||||
programming. But it *can* lead to some suprising behaviors, so please
|
programming. But it *can* lead to some surprising behaviors, so please
|
||||||
make sure to read :term:`slotted classes`.
|
make sure to read :term:`slotted classes`.
|
||||||
- *auto_exc=True*
|
- *auto_exc=True*
|
||||||
- *auto_detect=True*
|
- *auto_detect=True*
|
||||||
|
@ -131,10 +131,8 @@ def define(
|
||||||
for base_cls in cls.__bases__:
|
for base_cls in cls.__bases__:
|
||||||
if base_cls.__setattr__ is _frozen_setattrs:
|
if base_cls.__setattr__ is _frozen_setattrs:
|
||||||
if had_on_setattr:
|
if had_on_setattr:
|
||||||
raise ValueError(
|
msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)."
|
||||||
"Frozen classes can't use on_setattr "
|
raise ValueError(msg)
|
||||||
"(frozen-ness was inherited)."
|
|
||||||
)
|
|
||||||
|
|
||||||
on_setattr = setters.NO_OP
|
on_setattr = setters.NO_OP
|
||||||
break
|
break
|
||||||
|
@ -151,7 +149,7 @@ def define(
|
||||||
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
|
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
|
||||||
if maybe_cls is None:
|
if maybe_cls is None:
|
||||||
return wrap
|
return wrap
|
||||||
else:
|
|
||||||
return wrap(maybe_cls)
|
return wrap(maybe_cls)
|
||||||
|
|
||||||
|
|
||||||
|
@ -180,10 +178,9 @@ def field(
|
||||||
Identical to `attr.ib`, except keyword-only and with some arguments
|
Identical to `attr.ib`, except keyword-only and with some arguments
|
||||||
removed.
|
removed.
|
||||||
|
|
||||||
.. versionadded:: 22.3.0
|
.. versionadded:: 23.1.0
|
||||||
The *type* parameter has been re-added; mostly for
|
The *type* parameter has been re-added; mostly for `attrs.make_class`.
|
||||||
{func}`attrs.make_class`. Please note that type checkers ignore this
|
Please note that type checkers ignore this metadata.
|
||||||
metadata.
|
|
||||||
.. versionadded:: 20.1.0
|
.. versionadded:: 20.1.0
|
||||||
"""
|
"""
|
||||||
return attrib(
|
return attrib(
|
||||||
|
|
|
@ -70,21 +70,20 @@ def default_if_none(default=NOTHING, factory=None):
|
||||||
.. versionadded:: 18.2.0
|
.. versionadded:: 18.2.0
|
||||||
"""
|
"""
|
||||||
if default is NOTHING and factory is None:
|
if default is NOTHING and factory is None:
|
||||||
raise TypeError("Must pass either `default` or `factory`.")
|
msg = "Must pass either `default` or `factory`."
|
||||||
|
raise TypeError(msg)
|
||||||
|
|
||||||
if default is not NOTHING and factory is not None:
|
if default is not NOTHING and factory is not None:
|
||||||
raise TypeError(
|
msg = "Must pass either `default` or `factory` but not both."
|
||||||
"Must pass either `default` or `factory` but not both."
|
raise TypeError(msg)
|
||||||
)
|
|
||||||
|
|
||||||
if factory is not None:
|
if factory is not None:
|
||||||
default = Factory(factory)
|
default = Factory(factory)
|
||||||
|
|
||||||
if isinstance(default, Factory):
|
if isinstance(default, Factory):
|
||||||
if default.takes_self:
|
if default.takes_self:
|
||||||
raise ValueError(
|
msg = "`takes_self` is not supported by default_if_none."
|
||||||
"`takes_self` is not supported by default_if_none."
|
raise ValueError(msg)
|
||||||
)
|
|
||||||
|
|
||||||
def default_if_none_converter(val):
|
def default_if_none_converter(val):
|
||||||
if val is not None:
|
if val is not None:
|
||||||
|
@ -141,4 +140,5 @@ def to_bool(val):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# Raised when "val" is not hashable (e.g., lists)
|
# Raised when "val" is not hashable (e.g., lists)
|
||||||
pass
|
pass
|
||||||
raise ValueError(f"Cannot convert value to bool: {val}")
|
msg = f"Cannot convert value to bool: {val}"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
|
||||||
class FrozenError(AttributeError):
|
class FrozenError(AttributeError):
|
||||||
"""
|
"""
|
||||||
|
@ -13,7 +17,7 @@ class FrozenError(AttributeError):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
msg = "can't set attribute"
|
msg = "can't set attribute"
|
||||||
args = [msg]
|
args: ClassVar[tuple[str]] = [msg]
|
||||||
|
|
||||||
|
|
||||||
class FrozenInstanceError(FrozenError):
|
class FrozenInstanceError(FrozenError):
|
||||||
|
|
|
@ -13,6 +13,7 @@ def _split_what(what):
|
||||||
"""
|
"""
|
||||||
return (
|
return (
|
||||||
frozenset(cls for cls in what if isinstance(cls, type)),
|
frozenset(cls for cls in what if isinstance(cls, type)),
|
||||||
|
frozenset(cls for cls in what if isinstance(cls, str)),
|
||||||
frozenset(cls for cls in what if isinstance(cls, Attribute)),
|
frozenset(cls for cls in what if isinstance(cls, Attribute)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,14 +23,21 @@ def include(*what):
|
||||||
Include *what*.
|
Include *what*.
|
||||||
|
|
||||||
:param what: What to include.
|
:param what: What to include.
|
||||||
:type what: `list` of `type` or `attrs.Attribute`\\ s
|
:type what: `list` of classes `type`, field names `str` or
|
||||||
|
`attrs.Attribute`\\ s
|
||||||
|
|
||||||
:rtype: `callable`
|
:rtype: `callable`
|
||||||
|
|
||||||
|
.. versionchanged:: 23.1.0 Accept strings with field names.
|
||||||
"""
|
"""
|
||||||
cls, attrs = _split_what(what)
|
cls, names, attrs = _split_what(what)
|
||||||
|
|
||||||
def include_(attribute, value):
|
def include_(attribute, value):
|
||||||
return value.__class__ in cls or attribute in attrs
|
return (
|
||||||
|
value.__class__ in cls
|
||||||
|
or attribute.name in names
|
||||||
|
or attribute in attrs
|
||||||
|
)
|
||||||
|
|
||||||
return include_
|
return include_
|
||||||
|
|
||||||
|
@ -39,13 +47,20 @@ def exclude(*what):
|
||||||
Exclude *what*.
|
Exclude *what*.
|
||||||
|
|
||||||
:param what: What to exclude.
|
:param what: What to exclude.
|
||||||
:type what: `list` of classes or `attrs.Attribute`\\ s.
|
:type what: `list` of classes `type`, field names `str` or
|
||||||
|
`attrs.Attribute`\\ s.
|
||||||
|
|
||||||
:rtype: `callable`
|
:rtype: `callable`
|
||||||
|
|
||||||
|
.. versionchanged:: 23.3.0 Accept field name string as input argument
|
||||||
"""
|
"""
|
||||||
cls, attrs = _split_what(what)
|
cls, names, attrs = _split_what(what)
|
||||||
|
|
||||||
def exclude_(attribute, value):
|
def exclude_(attribute, value):
|
||||||
return value.__class__ not in cls and attribute not in attrs
|
return not (
|
||||||
|
value.__class__ in cls
|
||||||
|
or attribute.name in names
|
||||||
|
or attribute in attrs
|
||||||
|
)
|
||||||
|
|
||||||
return exclude_
|
return exclude_
|
||||||
|
|
|
@ -2,5 +2,5 @@ from typing import Any, Union
|
||||||
|
|
||||||
from . import Attribute, _FilterType
|
from . import Attribute, _FilterType
|
||||||
|
|
||||||
def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
|
def include(*what: Union[type, str, Attribute[Any]]) -> _FilterType[Any]: ...
|
||||||
def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
|
def exclude(*what: Union[type, str, Attribute[Any]]) -> _FilterType[Any]: ...
|
||||||
|
|
|
@ -97,23 +97,21 @@ class _InstanceOfValidator:
|
||||||
We use a callable class to be able to change the ``__repr__``.
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
"""
|
"""
|
||||||
if not isinstance(value, self.type):
|
if not isinstance(value, self.type):
|
||||||
raise TypeError(
|
msg = "'{name}' must be {type!r} (got {value!r} that is a {actual!r}).".format(
|
||||||
"'{name}' must be {type!r} (got {value!r} that is a "
|
|
||||||
"{actual!r}).".format(
|
|
||||||
name=attr.name,
|
name=attr.name,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
actual=value.__class__,
|
actual=value.__class__,
|
||||||
value=value,
|
value=value,
|
||||||
),
|
)
|
||||||
|
raise TypeError(
|
||||||
|
msg,
|
||||||
attr,
|
attr,
|
||||||
self.type,
|
self.type,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<instance_of validator for type {type!r}>".format(
|
return f"<instance_of validator for type {self.type!r}>"
|
||||||
type=self.type
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def instance_of(type):
|
def instance_of(type):
|
||||||
|
@ -142,20 +140,18 @@ class _MatchesReValidator:
|
||||||
We use a callable class to be able to change the ``__repr__``.
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
"""
|
"""
|
||||||
if not self.match_func(value):
|
if not self.match_func(value):
|
||||||
raise ValueError(
|
msg = "'{name}' must match regex {pattern!r} ({value!r} doesn't)".format(
|
||||||
"'{name}' must match regex {pattern!r}"
|
|
||||||
" ({value!r} doesn't)".format(
|
|
||||||
name=attr.name, pattern=self.pattern.pattern, value=value
|
name=attr.name, pattern=self.pattern.pattern, value=value
|
||||||
),
|
)
|
||||||
|
raise ValueError(
|
||||||
|
msg,
|
||||||
attr,
|
attr,
|
||||||
self.pattern,
|
self.pattern,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<matches_re validator for pattern {pattern!r}>".format(
|
return f"<matches_re validator for pattern {self.pattern!r}>"
|
||||||
pattern=self.pattern
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def matches_re(regex, flags=0, func=None):
|
def matches_re(regex, flags=0, func=None):
|
||||||
|
@ -176,22 +172,17 @@ def matches_re(regex, flags=0, func=None):
|
||||||
"""
|
"""
|
||||||
valid_funcs = (re.fullmatch, None, re.search, re.match)
|
valid_funcs = (re.fullmatch, None, re.search, re.match)
|
||||||
if func not in valid_funcs:
|
if func not in valid_funcs:
|
||||||
raise ValueError(
|
msg = "'func' must be one of {}.".format(
|
||||||
"'func' must be one of {}.".format(
|
|
||||||
", ".join(
|
", ".join(
|
||||||
sorted(
|
sorted(e and e.__name__ or "None" for e in set(valid_funcs))
|
||||||
e and e.__name__ or "None" for e in set(valid_funcs)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
if isinstance(regex, Pattern):
|
if isinstance(regex, Pattern):
|
||||||
if flags:
|
if flags:
|
||||||
raise TypeError(
|
msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead"
|
||||||
"'flags' can only be used with a string pattern; "
|
raise TypeError(msg)
|
||||||
"pass flags to re.compile() instead"
|
|
||||||
)
|
|
||||||
pattern = regex
|
pattern = regex
|
||||||
else:
|
else:
|
||||||
pattern = re.compile(regex, flags)
|
pattern = re.compile(regex, flags)
|
||||||
|
@ -215,20 +206,18 @@ class _ProvidesValidator:
|
||||||
We use a callable class to be able to change the ``__repr__``.
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
"""
|
"""
|
||||||
if not self.interface.providedBy(value):
|
if not self.interface.providedBy(value):
|
||||||
raise TypeError(
|
msg = "'{name}' must provide {interface!r} which {value!r} doesn't.".format(
|
||||||
"'{name}' must provide {interface!r} which {value!r} "
|
|
||||||
"doesn't.".format(
|
|
||||||
name=attr.name, interface=self.interface, value=value
|
name=attr.name, interface=self.interface, value=value
|
||||||
),
|
)
|
||||||
|
raise TypeError(
|
||||||
|
msg,
|
||||||
attr,
|
attr,
|
||||||
self.interface,
|
self.interface,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<provides validator for interface {interface!r}>".format(
|
return f"<provides validator for interface {self.interface!r}>"
|
||||||
interface=self.interface
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def provides(interface):
|
def provides(interface):
|
||||||
|
@ -269,9 +258,7 @@ class _OptionalValidator:
|
||||||
self.validator(inst, attr, value)
|
self.validator(inst, attr, value)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<optional validator for {what} or None>".format(
|
return f"<optional validator for {self.validator!r} or None>"
|
||||||
what=repr(self.validator)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def optional(validator):
|
def optional(validator):
|
||||||
|
@ -304,19 +291,16 @@ class _InValidator:
|
||||||
in_options = False
|
in_options = False
|
||||||
|
|
||||||
if not in_options:
|
if not in_options:
|
||||||
|
msg = f"'{attr.name}' must be in {self.options!r} (got {value!r})"
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"'{name}' must be in {options!r} (got {value!r})".format(
|
msg,
|
||||||
name=attr.name, options=self.options, value=value
|
|
||||||
),
|
|
||||||
attr,
|
attr,
|
||||||
self.options,
|
self.options,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<in_ validator with options {options!r}>".format(
|
return f"<in_ validator with options {self.options!r}>"
|
||||||
options=self.options
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def in_(options):
|
def in_(options):
|
||||||
|
@ -402,11 +386,8 @@ class _DeepIterable:
|
||||||
else f" {self.iterable_validator!r}"
|
else f" {self.iterable_validator!r}"
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
"<deep_iterable validator for{iterable_identifier}"
|
f"<deep_iterable validator for{iterable_identifier}"
|
||||||
" iterables of {member!r}>"
|
f" iterables of {self.member_validator!r}>"
|
||||||
).format(
|
|
||||||
iterable_identifier=iterable_identifier,
|
|
||||||
member=self.member_validator,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -477,19 +458,11 @@ class _NumberValidator:
|
||||||
We use a callable class to be able to change the ``__repr__``.
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
"""
|
"""
|
||||||
if not self.compare_func(value, self.bound):
|
if not self.compare_func(value, self.bound):
|
||||||
raise ValueError(
|
msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}"
|
||||||
"'{name}' must be {op} {bound}: {value}".format(
|
raise ValueError(msg)
|
||||||
name=attr.name,
|
|
||||||
op=self.compare_op,
|
|
||||||
bound=self.bound,
|
|
||||||
value=value,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Validator for x {op} {bound}>".format(
|
return f"<Validator for x {self.compare_op} {self.bound}>"
|
||||||
op=self.compare_op, bound=self.bound
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def lt(val):
|
def lt(val):
|
||||||
|
@ -549,11 +522,8 @@ class _MaxLengthValidator:
|
||||||
We use a callable class to be able to change the ``__repr__``.
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
"""
|
"""
|
||||||
if len(value) > self.max_length:
|
if len(value) > self.max_length:
|
||||||
raise ValueError(
|
msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}"
|
||||||
"Length of '{name}' must be <= {max}: {len}".format(
|
raise ValueError(msg)
|
||||||
name=attr.name, max=self.max_length, len=len(value)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<max_len validator for {self.max_length}>"
|
return f"<max_len validator for {self.max_length}>"
|
||||||
|
@ -580,11 +550,8 @@ class _MinLengthValidator:
|
||||||
We use a callable class to be able to change the ``__repr__``.
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
"""
|
"""
|
||||||
if len(value) < self.min_length:
|
if len(value) < self.min_length:
|
||||||
raise ValueError(
|
msg = f"Length of '{attr.name}' must be => {self.min_length}: {len(value)}"
|
||||||
"Length of '{name}' must be => {min}: {len}".format(
|
raise ValueError(msg)
|
||||||
name=attr.name, min=self.min_length, len=len(value)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<min_len validator for {self.min_length}>"
|
return f"<min_len validator for {self.min_length}>"
|
||||||
|
@ -611,22 +578,16 @@ class _SubclassOfValidator:
|
||||||
We use a callable class to be able to change the ``__repr__``.
|
We use a callable class to be able to change the ``__repr__``.
|
||||||
"""
|
"""
|
||||||
if not issubclass(value, self.type):
|
if not issubclass(value, self.type):
|
||||||
|
msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})."
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"'{name}' must be a subclass of {type!r} "
|
msg,
|
||||||
"(got {value!r}).".format(
|
|
||||||
name=attr.name,
|
|
||||||
type=self.type,
|
|
||||||
value=value,
|
|
||||||
),
|
|
||||||
attr,
|
attr,
|
||||||
self.type,
|
self.type,
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<subclass_of validator for type {type!r}>".format(
|
return f"<subclass_of validator for type {self.type!r}>"
|
||||||
type=self.type
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _subclass_of(type):
|
def _subclass_of(type):
|
||||||
|
@ -680,7 +641,7 @@ class _NotValidator:
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (
|
return (
|
||||||
"<not_ validator wrapping {what!r}, " "capturing {exc_types!r}>"
|
"<not_ validator wrapping {what!r}, capturing {exc_types!r}>"
|
||||||
).format(
|
).format(
|
||||||
what=self.validator,
|
what=self.validator,
|
||||||
exc_types=self.exc_types,
|
exc_types=self.exc_types,
|
||||||
|
|
Loading…
Reference in a new issue