back to Claude Sonnet 3.5 - Fill-in summary
Claude Sonnet 3.5 - Fill-in: attrs
Failed to run pytests for test tests
Traceback (most recent call last):
File "/testbed/.venv/bin/pytest", line 8, in <module>
sys.exit(console_main())
^^^^^^^^^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 201, in console_main
code = main()
^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 156, in main
config = _prepareconfig(args, plugins)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 341, in _prepareconfig
config = pluginmanager.hook.pytest_cmdline_parse(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/pluggy/_hooks.py", line 513, in __call__
return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 120, in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 139, in _multicall
raise exception.with_traceback(exception.__traceback__)
File "/testbed/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 122, in _multicall
teardown.throw(exception) # type: ignore[union-attr]
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/helpconfig.py", line 105, in pytest_cmdline_parse
config = yield
^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/pluggy/_callers.py", line 103, in _multicall
res = hook_impl.function(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1140, in pytest_cmdline_parse
self.parse(args)
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1494, in parse
self._preparse(args, addopts=addopts)
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1381, in _preparse
self.pluginmanager.load_setuptools_entrypoints("pytest11")
File "/testbed/.venv/lib/python3.12/site-packages/pluggy/_manager.py", line 421, in load_setuptools_entrypoints
plugin = ep.load()
^^^^^^^^^
File "/root/.local/share/uv/python/cpython-3.12.6-linux-x86_64-gnu/lib/python3.12/importlib/metadata/__init__.py", line 205, in load
module = import_module(match.group('module'))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/.local/share/uv/python/cpython-3.12.6-linux-x86_64-gnu/lib/python3.12/importlib/__init__.py", line 90, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
File "/testbed/.venv/lib/python3.12/site-packages/_pytest/assertion/rewrite.py", line 184, in exec_module
exec(co, module.__dict__)
File "/testbed/.venv/lib/python3.12/site-packages/pytest_mypy_plugins/collect.py", line 20, in <module>
import jsonschema
File "/testbed/.venv/lib/python3.12/site-packages/jsonschema/__init__.py", line 13, in <module>
from jsonschema._format import FormatChecker
File "/testbed/.venv/lib/python3.12/site-packages/jsonschema/_format.py", line 11, in <module>
from jsonschema.exceptions import FormatError
File "/testbed/.venv/lib/python3.12/site-packages/jsonschema/exceptions.py", line 14, in <module>
from attrs import define
File "/testbed/src/attrs/__init__.py", line 3, in <module>
from attr import (
File "/testbed/src/attr/__init__.py", line 10, in <module>
from . import converters, exceptions, filters, setters, validators
File "/testbed/src/attr/converters.py", line 6, in <module>
from ._make import NOTHING, Factory, pipe
File "/testbed/src/attr/_make.py", line 725, in <module>
_a = [Attribute(name=name, default=NOTHING, validator=None, repr=True, cmp=
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/testbed/src/attr/_make.py", line 673, in __init__
eq, eq_key, order, order_key = _determine_attrib_eq_order(cmp,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: cannot unpack non-iterable NoneType object
Patch diff
diff --git a/src/attr/_cmp.py b/src/attr/_cmp.py
index 875bde6..577859d 100644
--- a/src/attr/_cmp.py
+++ b/src/attr/_cmp.py
@@ -43,32 +43,67 @@ def cmp_using(eq=None, lt=None, le=None, gt=None, ge=None,
.. versionadded:: 21.1.0
"""
- pass
+ def _make_method(op):
+ def method(self, other):
+ if require_same_type and not isinstance(other, type(self)):
+ return NotImplemented
+ return op(self.value, other.value)
+ return method
+
+ class Comparable:
+ __slots__ = ('value',)
+
+ def __init__(self, value):
+ self.value = value
+
+ if eq is not None:
+ __eq__ = _make_method(eq)
+ if lt is not None:
+ __lt__ = _make_method(lt)
+ if le is not None:
+ __le__ = _make_method(le)
+ if gt is not None:
+ __gt__ = _make_method(gt)
+ if ge is not None:
+ __ge__ = _make_method(ge)
+
+ if eq is not None:
+ __ne__ = _make_ne(__eq__)
+
+ Comparable.__name__ = class_name
+ return Comparable
def _make_init():
"""
Create __init__ method.
"""
- pass
+ def __init__(self, value):
+ self.value = value
+ return __init__
def _make_operator(name, func):
"""
Create operator method.
"""
- pass
+ def method(self, other):
+ if not _is_comparable_to(self, other):
+ return NotImplemented
+ return func(self.value, other.value)
+ method.__name__ = f'__{name}__'
+ return method
def _is_comparable_to(self, other):
"""
Check whether `other` is comparable to `self`.
"""
- pass
+ return isinstance(other, type(self))
def _check_same_type(self, other):
"""
Return True if *self* and *other* are of the same type, False otherwise.
"""
- pass
+ return isinstance(other, type(self))
diff --git a/src/attr/_compat.py b/src/attr/_compat.py
index 1afacff..a784ac1 100644
--- a/src/attr/_compat.py
+++ b/src/attr/_compat.py
@@ -28,7 +28,7 @@ else:
"""
Get annotations for *cls*.
"""
- pass
+ return getattr(cls, '__annotations__', {})
class _AnnotationExtractor:
@@ -48,13 +48,21 @@ class _AnnotationExtractor:
"""
Return the type annotation of the first argument if it's not empty.
"""
- pass
+ if self.sig is None:
+ return None
+ params = list(self.sig.parameters.values())
+ if not params:
+ return None
+ first_param = params[0]
+ return first_param.annotation if first_param.annotation != inspect.Parameter.empty else None
def get_return_type(self):
"""
Return the return type if it's not empty.
"""
- pass
+ if self.sig is None:
+ return None
+ return self.sig.return_annotation if self.sig.return_annotation != inspect.Signature.empty else None
repr_context = threading.local()
@@ -62,4 +70,6 @@ repr_context = threading.local()
def get_generic_base(cl):
"""If this is a generic class (A[str]), return the generic base for it."""
- pass
+ if isinstance(cl, _GenericAlias):
+ return cl.__origin__
+ return None
diff --git a/src/attr/_config.py b/src/attr/_config.py
index cfa2d9b..a04e731 100644
--- a/src/attr/_config.py
+++ b/src/attr/_config.py
@@ -10,7 +10,8 @@ def set_run_validators(run):
moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()`
instead.
"""
- pass
+ global _run_validators
+ _run_validators = run
def get_run_validators():
@@ -21,4 +22,4 @@ def get_run_validators():
moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()`
instead.
"""
- pass
+ return _run_validators
diff --git a/src/attr/_funcs.py b/src/attr/_funcs.py
index 4c9728a..68e894d 100644
--- a/src/attr/_funcs.py
+++ b/src/attr/_funcs.py
@@ -50,7 +50,27 @@ def asdict(inst, recurse=True, filter=None, dict_factory=dict,
.. versionadded:: 21.3.0
If a dict has a collection for a key, it is serialized as a tuple.
"""
- pass
+ 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:
+ if has(v.__class__):
+ v = asdict(v, recurse=True, filter=filter, dict_factory=dict_factory,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer)
+ elif isinstance(v, (tuple, list, set, frozenset)):
+ v = _asdict_anything(v, False, filter, dict_factory,
+ retain_collection_types, value_serializer)
+ elif isinstance(v, dict):
+ v = _asdict_anything(v, True, filter, dict_factory,
+ retain_collection_types, value_serializer)
+ rv[a.name] = v
+ return rv
def _asdict_anything(val, is_key, filter, dict_factory,
@@ -58,7 +78,21 @@ def _asdict_anything(val, is_key, filter, dict_factory,
"""
``asdict`` only works on attrs instances, this works on anything.
"""
- pass
+ if isinstance(val, dict):
+ return dict_factory((
+ _asdict_anything(k, True, filter, dict_factory, retain_collection_types, value_serializer),
+ _asdict_anything(v, False, filter, dict_factory, retain_collection_types, value_serializer)
+ ) for k, v in val.items())
+ elif isinstance(val, (list, tuple)) and not (retain_collection_types and isinstance(val, tuple)):
+ return [_asdict_anything(i, is_key, filter, dict_factory, retain_collection_types, value_serializer) for i in val]
+ elif isinstance(val, set) and not retain_collection_types:
+ return [_asdict_anything(i, is_key, filter, dict_factory, retain_collection_types, value_serializer) for i in val]
+ elif has(val.__class__):
+ return asdict(val, filter=filter, dict_factory=dict_factory,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer)
+ else:
+ return val
def astuple(inst, recurse=True, filter=None, tuple_factory=tuple,
@@ -98,7 +132,22 @@ def astuple(inst, recurse=True, filter=None, tuple_factory=tuple,
.. versionadded:: 16.2.0
"""
- pass
+ attrs = fields(inst.__class__)
+ rv = []
+ for a in attrs:
+ v = getattr(inst, a.name)
+ if filter is not None and not filter(a, v):
+ continue
+ if recurse:
+ if has(v.__class__):
+ v = astuple(v, recurse=True, filter=filter, tuple_factory=tuple_factory,
+ retain_collection_types=retain_collection_types)
+ elif isinstance(v, (tuple, list, set, frozenset)):
+ v = _astuple_anything(v, filter, tuple_factory, retain_collection_types)
+ elif isinstance(v, dict):
+ v = _astuple_anything(v.items(), filter, tuple_factory, retain_collection_types)
+ rv.append(v)
+ return tuple_factory(rv)
def has(cls):
@@ -114,7 +163,9 @@ def has(cls):
Returns:
bool:
"""
- pass
+ if not isinstance(cls, type):
+ raise TypeError("has() requires a class")
+ return hasattr(cls, "__attrs_attrs__")
def assoc(inst, **changes):
@@ -149,7 +200,16 @@ def assoc(inst, **changes):
removed du to the slightly different approach compared to
`attrs.evolve`, though.
"""
- pass
+ import warnings
+ warnings.warn("assoc is deprecated, use attrs.evolve instead.", DeprecationWarning, stacklevel=2)
+
+ new_inst = copy.deepcopy(inst)
+ attrs = fields(inst.__class__)
+ for attr_name, new_value in changes.items():
+ if not any(a.name == attr_name for a in attrs):
+ raise AttrsAttributeNotFoundError(f"'{attr_name}' is not an attrs attribute on {inst.__class__}")
+ setattr(new_inst, attr_name, new_value)
+ return new_inst
def evolve(*args, **changes):
@@ -185,7 +245,18 @@ def evolve(*args, **changes):
.. versionchanged:: 24.1.0
*inst* can't be passed as a keyword argument anymore.
"""
- pass
+ if not args:
+ raise TypeError("evolve() missing 1 required positional argument: 'inst'")
+ inst = args[0]
+ if not has(inst.__class__):
+ raise NotAnAttrsClassError(f"{inst.__class__.__name__} is not an attrs-decorated class.")
+
+ new_inst = copy.deepcopy(inst)
+ for attr_name, new_value in changes.items():
+ if not hasattr(new_inst, attr_name):
+ raise TypeError(f"'{attr_name}' is not an initialization argument for {inst.__class__.__name__}")
+ setattr(new_inst, attr_name, new_value)
+ return new_inst
def resolve_types(cls, globalns=None, localns=None, attribs=None,
@@ -238,4 +309,20 @@ def resolve_types(cls, globalns=None, localns=None, attribs=None,
.. versionadded:: 21.1.0 *attribs*
.. versionadded:: 23.1.0 *include_extras*
"""
- pass
+ import typing
+
+ if not isinstance(cls, type):
+ raise TypeError("resolve_types() requires a class.")
+
+ if attribs is None:
+ if not has(cls):
+ raise NotAnAttrsClassError(f"{cls.__name__} is not an attrs-decorated class.")
+ attribs = fields(cls)
+
+ hints = typing.get_type_hints(cls, globalns=globalns, localns=localns, include_extras=include_extras)
+
+ for a in attribs:
+ if a.name in hints:
+ a.type = hints[a.name]
+
+ return cls
diff --git a/src/attr/_make.py b/src/attr/_make.py
index f3ed380..7775983 100644
--- a/src/attr/_make.py
+++ b/src/attr/_make.py
@@ -114,14 +114,19 @@ def _compile_and_eval(script, globs, locs=None, filename=''):
Evaluate the script with the given global (globs) and local (locs)
variables.
"""
- pass
+ if locs is None:
+ locs = {}
+ code = compile(script, filename, 'exec')
+ eval(code, globs, locs)
+ return locs
def _make_method(name, script, filename, globs, locals=None):
"""
Create the method with the script given and return the method object.
"""
- pass
+ locs = _compile_and_eval(script, globs, locals, filename)
+ return locs[name]
def _make_attr_tuple_class(cls_name, attr_names):
@@ -134,7 +139,12 @@ def _make_attr_tuple_class(cls_name, attr_names):
__slots__ = ()
x = property(itemgetter(0))
"""
- pass
+ attr_class_name = f"{cls_name}Attributes"
+ attr_class_body = {
+ "__slots__": (),
+ **{name: property(itemgetter(index)) for index, name in enumerate(attr_names)}
+ }
+ return type(attr_class_name, (tuple,), attr_class_body)
_Attributes = _make_attr_tuple_class('_Attributes', ['attrs', 'base_attrs',
@@ -149,14 +159,16 @@ def _is_class_var(annot):
annotations which would put attrs-based classes at a performance
disadvantage compared to plain old classes.
"""
- pass
+ return (isinstance(annot, str) and any(
+ annot.startswith(cls_var) for cls_var in _CLASSVAR_PREFIXES
+ )) or (not isinstance(annot, str) and getattr(annot, "__origin__", None) is typing.ClassVar)
def _has_own_attribute(cls, attrib_name):
"""
Check whether *cls* defines *attrib_name* (and doesn't just inherit it).
"""
- pass
+ return attrib_name in cls.__dict__
def _collect_base_attrs(cls, taken_attr_names):
diff --git a/src/attr/_next_gen.py b/src/attr/_next_gen.py
index 067dc2f..89888b6 100644
--- a/src/attr/_next_gen.py
+++ b/src/attr/_next_gen.py
@@ -313,7 +313,32 @@ def define(maybe_cls=None, *, these=None, repr=None, unsafe_hash=None, hash
for backwards-compatibility have been removed.
"""
- pass
+ def wrap(cls):
+ return attrs(
+ maybe_cls=cls,
+ these=these,
+ repr=repr,
+ unsafe_hash=unsafe_hash,
+ 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,
+ getstate_setstate=getstate_setstate,
+ on_setattr=on_setattr,
+ field_transformer=field_transformer,
+ match_args=match_args,
+ )
+
+ return wrap(maybe_cls) if maybe_cls is not None else wrap
mutable = define
@@ -476,7 +501,22 @@ def field(*, default=NOTHING, validator=None, repr=True, hash=None, init=
`attr.ib`
"""
- pass
+ return attrib(
+ default=default,
+ validator=validator,
+ repr=repr,
+ hash=hash,
+ init=init,
+ metadata=metadata,
+ type=type,
+ converter=converter,
+ factory=factory,
+ kw_only=kw_only,
+ eq=eq,
+ order=order,
+ on_setattr=on_setattr,
+ alias=alias,
+ )
def asdict(inst, *, recurse=True, filter=None, value_serializer=None):
@@ -486,7 +526,14 @@ def asdict(inst, *, recurse=True, filter=None, value_serializer=None):
.. versionadded:: 21.3.0
"""
- pass
+ return _asdict(
+ inst,
+ recurse=recurse,
+ filter=filter,
+ dict_factory=dict,
+ retain_collection_types=True,
+ value_serializer=value_serializer,
+ )
def astuple(inst, *, recurse=True, filter=None):
@@ -496,4 +543,10 @@ def astuple(inst, *, recurse=True, filter=None):
.. versionadded:: 21.3.0
"""
- pass
+ return _astuple(
+ inst,
+ recurse=recurse,
+ filter=filter,
+ tuple_factory=tuple,
+ retain_collection_types=True,
+ )
diff --git a/src/attr/_version_info.py b/src/attr/_version_info.py
index 6691f84..a7a4b62 100644
--- a/src/attr/_version_info.py
+++ b/src/attr/_version_info.py
@@ -35,7 +35,17 @@ class VersionInfo:
"""
Parse *s* and return a _VersionInfo.
"""
- pass
+ parts = s.split('.')
+ if len(parts) < 3:
+ raise ValueError("Invalid version string")
+
+ year = int(parts[0])
+ minor = int(parts[1])
+ micro_release = parts[2].split('-')
+ micro = int(micro_release[0])
+ releaselevel = "final" if len(micro_release) == 1 else micro_release[1]
+
+ return cls(year, minor, micro, releaselevel)
def _ensure_tuple(self, other):
"""
@@ -44,7 +54,19 @@ class VersionInfo:
Returns a possibly transformed *other* and ourselves as a tuple of
the same length as *other*.
"""
- pass
+ if not isinstance(other, tuple):
+ raise NotImplementedError("Can only compare with tuples")
+
+ if len(other) > 4:
+ raise NotImplementedError("Can only compare with tuples of length 1-4")
+
+ our_tuple = astuple(self)
+
+ if len(other) < 4:
+ other = other + (None,) * (4 - len(other))
+ our_tuple = our_tuple[:len(other)]
+
+ return our_tuple, other
def __eq__(self, other):
try:
diff --git a/src/attr/converters.py b/src/attr/converters.py
index df5c697..c803db9 100644
--- a/src/attr/converters.py
+++ b/src/attr/converters.py
@@ -21,7 +21,12 @@ def optional(converter):
.. versionadded:: 17.1.0
"""
- pass
+ def optional_converter(value):
+ if value is None:
+ return None
+ return converter(value)
+
+ return optional_converter
def default_if_none(default=NOTHING, factory=None):
@@ -50,7 +55,30 @@ def default_if_none(default=NOTHING, factory=None):
.. versionadded:: 18.2.0
"""
- pass
+ 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`, not both.")
+ if isinstance(default, Factory) and default.takes_self:
+ raise ValueError("Factory instances with `takes_self=True` are not supported.")
+
+ if factory is not None:
+ def default_if_none_converter(value):
+ if value is None:
+ return factory()
+ return value
+ elif isinstance(default, Factory):
+ def default_if_none_converter(value):
+ if value is None:
+ return default.factory()
+ return value
+ else:
+ def default_if_none_converter(value):
+ if value is None:
+ return default
+ return value
+
+ return default_if_none_converter
def to_bool(val):
@@ -81,4 +109,14 @@ def to_bool(val):
.. versionadded:: 21.3.0
"""
- pass
+ if isinstance(val, bool):
+ return val
+ if isinstance(val, (int, float)):
+ return bool(val)
+ if isinstance(val, str):
+ val = val.lower()
+ if val in ("true", "t", "yes", "y", "on", "1"):
+ return True
+ if val in ("false", "f", "no", "n", "off", "0"):
+ return False
+ raise ValueError(f"Cannot convert {val!r} to bool")
diff --git a/src/attr/filters.py b/src/attr/filters.py
index c3c2781..058b593 100644
--- a/src/attr/filters.py
+++ b/src/attr/filters.py
@@ -8,7 +8,11 @@ def _split_what(what):
"""
Returns a tuple of `frozenset`s of classes and attributes.
"""
- pass
+ classes = frozenset(cls for cls in what if isinstance(cls, type))
+ attrs = frozenset(
+ attr for attr in what if isinstance(attr, (str, Attribute))
+ )
+ return classes, attrs
def include(*what):
@@ -26,7 +30,16 @@ def include(*what):
.. versionchanged:: 23.1.0 Accept strings with field names.
"""
- pass
+ classes, attributes = _split_what(what)
+
+ def include_filter(attribute, value):
+ return (
+ attribute.__class__ in classes
+ or attribute.name in attributes
+ or attribute in attributes
+ )
+
+ return include_filter
def exclude(*what):
@@ -44,4 +57,13 @@ def exclude(*what):
.. versionchanged:: 23.3.0 Accept field name string as input argument
"""
- pass
+ classes, attributes = _split_what(what)
+
+ def exclude_filter(attribute, value):
+ return not (
+ attribute.__class__ in classes
+ or attribute.name in attributes
+ or attribute in attributes
+ )
+
+ return exclude_filter
diff --git a/src/attr/setters.py b/src/attr/setters.py
index 1bb6a12..b3d15fd 100644
--- a/src/attr/setters.py
+++ b/src/attr/setters.py
@@ -11,16 +11,20 @@ def pipe(*setters):
.. versionadded:: 20.1.0
"""
- pass
+ def wrapped(instance, attribute, value):
+ for setter in setters:
+ value = setter(instance, attribute, value)
+ return value
+ return wrapped
-def frozen(_, __, ___):
+def frozen(instance, attribute, value):
"""
Prevent an attribute to be modified.
.. versionadded:: 20.1.0
"""
- pass
+ raise FrozenAttributeError("Can't set attribute: frozen")
def validate(instance, attrib, new_value):
@@ -29,7 +33,9 @@ def validate(instance, attrib, new_value):
.. versionadded:: 20.1.0
"""
- pass
+ if attrib.validator is not None:
+ attrib.validator(instance, attrib, new_value)
+ return new_value
def convert(instance, attrib, new_value):
@@ -39,7 +45,9 @@ def convert(instance, attrib, new_value):
.. versionadded:: 20.1.0
"""
- pass
+ if attrib.converter is not None:
+ return attrib.converter(new_value)
+ return new_value
NO_OP = object()
diff --git a/src/attr/validators.py b/src/attr/validators.py
index d98967a..b9e0824 100644
--- a/src/attr/validators.py
+++ b/src/attr/validators.py
@@ -30,7 +30,7 @@ def set_disabled(disabled):
.. versionadded:: 21.3.0
"""
- pass
+ set_run_validators(not disabled)
def get_disabled():
@@ -42,7 +42,7 @@ def get_disabled():
.. versionadded:: 21.3.0
"""
- pass
+ return not get_run_validators()
@contextmanager
@@ -56,7 +56,12 @@ def disabled():
.. versionadded:: 21.3.0
"""
- pass
+ original_run_validators = get_run_validators()
+ set_run_validators(False)
+ try:
+ yield
+ finally:
+ set_run_validators(original_run_validators)
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -91,7 +96,7 @@ def instance_of(type):
With a human readable error message, the attribute (of type
`attrs.Attribute`), the expected type, and the value it got.
"""
- pass
+ return _InstanceOfValidator(type)
@attrs(repr=False, frozen=True, slots=True)
@@ -134,7 +139,19 @@ def matches_re(regex, flags=0, func=None):
.. versionadded:: 19.2.0
.. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern.
"""
- pass
+ if isinstance(regex, Pattern):
+ compiled_regex = regex
+ else:
+ compiled_regex = re.compile(regex, flags)
+
+ if func is None:
+ match_func = compiled_regex.fullmatch
+ elif func in (re.fullmatch, re.search, re.match):
+ match_func = lambda value: func(compiled_regex, value)
+ else:
+ raise ValueError("func must be re.fullmatch, re.search, or re.match")
+
+ return _MatchesReValidator(compiled_regex, match_func)
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -165,7 +182,9 @@ def optional(validator):
.. versionchanged:: 17.1.0 *validator* can be a list of validators.
.. versionchanged:: 23.1.0 *validator* can also be a tuple of validators.
"""
- pass
+ if isinstance(validator, (list, tuple)):
+ validator = and_(*validator)
+ return _OptionalValidator(validator)
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -216,7 +235,9 @@ def in_(options):
*options* that are a list, dict, or a set are now transformed into a
tuple to keep the validator hashable.
"""
- pass
+ if isinstance(options, (list, dict, set)):
+ options = tuple(options)
+ return _InValidator(options, options)
@attrs(repr=False, slots=False, unsafe_hash=True)
@@ -250,7 +271,7 @@ def is_callable():
With a human readable error message containing the attribute
(`attrs.Attribute`) name, and the value it got.
"""
- pass
+ return _IsCallableValidator()
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -291,7 +312,7 @@ def deep_iterable(member_validator, iterable_validator=None):
.. versionadded:: 19.1.0
"""
- pass
+ return _DeepIterable(member_validator, iterable_validator)
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -333,7 +354,7 @@ def deep_mapping(key_validator, value_validator, mapping_validator=None):
Raises:
TypeError: if any sub-validators fail
"""
- pass
+ return _DeepMapping(key_validator, value_validator, mapping_validator)
@attrs(repr=False, frozen=True, slots=True)
@@ -368,7 +389,7 @@ def lt(val):
.. versionadded:: 21.3.0
"""
- pass
+ return _NumberValidator(val, "<", operator.lt)
def le(val):
@@ -383,7 +404,7 @@ def le(val):
.. versionadded:: 21.3.0
"""
- pass
+ return _NumberValidator(val, "<=", operator.le)
def ge(val):
@@ -398,7 +419,7 @@ def ge(val):
.. versionadded:: 21.3.0
"""
- pass
+ return _NumberValidator(val, ">=", operator.ge)
def gt(val):
@@ -406,14 +427,14 @@ def gt(val):
A validator that raises `ValueError` if the initializer is called with a
number smaller or equal to *val*.
- The validator uses `operator.ge` to compare the values.
+ The validator uses `operator.gt` to compare the values.
Args:
val: Exclusive lower bound for values
.. versionadded:: 21.3.0
"""
- pass
+ return _NumberValidator(val, ">", operator.gt)
@attrs(repr=False, frozen=True, slots=True)
@@ -444,7 +465,7 @@ def max_len(length):
.. versionadded:: 21.3.0
"""
- pass
+ return _MaxLengthValidator(length)
@attrs(repr=False, frozen=True, slots=True)
@@ -475,7 +496,7 @@ def min_len(length):
.. versionadded:: 22.1.0
"""
- pass
+ return _MinLengthValidator(length)
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -510,7 +531,7 @@ def _subclass_of(type):
With a human readable error message, the attribute (of type
`attrs.Attribute`), the expected type, and the value it got.
"""
- pass
+ return _SubclassOfValidator(type)
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -566,7 +587,7 @@ def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)):
.. versionadded:: 22.2.0
"""
- pass
+ return _NotValidator(validator, msg, exc_types)
@attrs(repr=False, slots=True, unsafe_hash=True)
@@ -607,4 +628,4 @@ def or_(*validators):
.. versionadded:: 24.1.0
"""
- pass
+ return _OrValidator(validators)