Add attr.valid
This commit is contained in:
parent
f7597c795f
commit
2cab907370
|
@ -7,6 +7,7 @@ from ._funcs import (
|
|||
assoc,
|
||||
fields,
|
||||
has,
|
||||
valid,
|
||||
)
|
||||
from ._make import (
|
||||
Attribute,
|
||||
|
@ -40,5 +41,6 @@ __all__ = [
|
|||
"ib",
|
||||
"make_class",
|
||||
"s",
|
||||
"valid",
|
||||
"validators",
|
||||
]
|
||||
|
|
|
@ -92,3 +92,15 @@ def assoc(inst, **changes):
|
|||
)
|
||||
setattr(new, k, v)
|
||||
return new
|
||||
|
||||
|
||||
def valid(inst):
|
||||
"""
|
||||
Validate all attributes on *inst* that have a validator.
|
||||
|
||||
Leaves all exceptions through.
|
||||
|
||||
:param inst: Instance of a class with ``attrs`` attributes.
|
||||
"""
|
||||
for a in fields(inst.__class__):
|
||||
a.validator(a, getattr(inst, a.name))
|
||||
|
|
17
docs/api.rst
17
docs/api.rst
|
@ -150,6 +150,23 @@ Helpers
|
|||
False
|
||||
|
||||
|
||||
.. autofunction:: valid
|
||||
|
||||
For example:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> @attr.s
|
||||
... class C(object):
|
||||
... x = attr.ib(validator=attr.validators.instance_of(int))
|
||||
>>> i = C(1)
|
||||
>>> i.x = "1"
|
||||
>>> attr.valid(i)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: ("'x' must be <type 'int'> (got '1' that is a <type 'str'>).", Attribute(name='x', default=NOTHING, validator=<instance_of validator for type <type 'int'>>, no_repr=False, no_cmp=False, no_hash=False, no_init=False), <type 'int'>, '1')
|
||||
|
||||
|
||||
.. _api_validators:
|
||||
|
||||
Validators
|
||||
|
|
|
@ -120,6 +120,17 @@ If the value does not pass the validator's standards, it just raises an appropri
|
|||
...
|
||||
ValueError: 'x' has to be smaller than 5!
|
||||
|
||||
``attrs`` won't intercept your changes to those attributes but you can always call :func:``attr.valid`` on any instance to verify, that it's still valid:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> i = C(4)
|
||||
>>> i.x = 5 # works, no magic here
|
||||
>>> attr.valid(i)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: 'x' has to be smaller than 5!
|
||||
|
||||
``attrs`` ships with a bunch of validators, make sure to :ref:`check them out <api_validators>` before writing your own:
|
||||
|
||||
.. doctest::
|
||||
|
|
|
@ -13,11 +13,13 @@ from attr._funcs import (
|
|||
assoc,
|
||||
fields,
|
||||
has,
|
||||
valid,
|
||||
)
|
||||
from attr._make import (
|
||||
Attribute,
|
||||
attr,
|
||||
attributes,
|
||||
make_class,
|
||||
)
|
||||
|
||||
|
||||
|
@ -167,3 +169,30 @@ class TestAssoc(object):
|
|||
assert (
|
||||
"y is not an attrs attribute on {cl!r}.".format(cl=C),
|
||||
) == e.value.args
|
||||
|
||||
|
||||
class TestValid(object):
|
||||
"""
|
||||
Tests for `valid`.
|
||||
"""
|
||||
def test_success(self):
|
||||
"""
|
||||
If the validator suceeds, nothing gets raised.
|
||||
"""
|
||||
C = make_class("C", {"x": attr(validator=lambda _, __: None)})
|
||||
valid(C(1))
|
||||
|
||||
def test_propagates(self):
|
||||
"""
|
||||
The exception of the validator is handed through.
|
||||
"""
|
||||
def raiser(_, value):
|
||||
if value == 42:
|
||||
raise FloatingPointError
|
||||
|
||||
C = make_class("C", {"x": attr(validator=raiser)})
|
||||
i = C(1)
|
||||
i.x = 42
|
||||
|
||||
with pytest.raises(FloatingPointError):
|
||||
valid(i)
|
||||
|
|
Loading…
Reference in New Issue