Skip to content

Commit

Permalink
Add "no_run_validators()" context manager
Browse files Browse the repository at this point in the history
  • Loading branch information
sscherfke committed Nov 2, 2021
1 parent 5a368d8 commit 8bf5cb8
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 1 deletion.
10 changes: 10 additions & 0 deletions docs/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,16 @@ And finally you can disable validators globally:
...
TypeError: ("'x' must be <class 'int'> (got '128' that is a <class 'str'>).", Attribute(name='x', default=NOTHING, validator=[<instance_of validator for type <class 'int'>>, <function fits_byte at 0x10fd7a0d0>], repr=True, cmp=True, hash=True, init=True, metadata=mappingproxy({}), type=None, converter=None), <class 'int'>, '128')

You can achieve the same by using the context manager:

>>> with attrs.no_run_validators():
... C("128")
C(x='128')
>>> C("128")
Traceback (most recent call last):
...
TypeError: ("'x' must be <class 'int'> (got '128' that is a <class 'str'>).", Attribute(name='x', default=NOTHING, validator=[<instance_of validator for type <class 'int'>>, <function fits_byte at 0x10fd7a0d0>], repr=True, cmp=True, hash=True, init=True, metadata=mappingproxy({}), type=None, converter=None), <class 'int'>, '128')


.. _converters:

Expand Down
2 changes: 1 addition & 1 deletion src/attr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from . import converters, exceptions, filters, setters, validators
from ._cmp import cmp_using
from ._config import get_run_validators, set_run_validators
from ._config import get_run_validators, no_run_validators, set_run_validators
from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
from ._make import (
NOTHING,
Expand Down
2 changes: 2 additions & 0 deletions src/attr/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import sys
from typing import (
Any,
Callable,
ContextManager,
Dict,
Generic,
List,
Expand Down Expand Up @@ -473,6 +474,7 @@ def evolve(inst: _T, **changes: Any) -> _T: ...

def set_run_validators(run: bool) -> None: ...
def get_run_validators() -> bool: ...
def no_run_validators() -> ContextManager[None]: ...

# aliases --

Expand Down
15 changes: 15 additions & 0 deletions src/attr/_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from __future__ import absolute_import, division, print_function
from contextlib import contextmanager


__all__ = ["set_run_validators", "get_run_validators"]
Expand All @@ -21,3 +22,17 @@ def get_run_validators():
Return whether or not validators are run.
"""
return _run_validators


@contextmanager
def no_run_validators():
"""
Context manager that disables running validators within its context.
.. versionadded:: 21.3.0
"""
set_run_validators(False)
try:
yield
finally:
set_run_validators(True)
22 changes: 22 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,25 @@ def test_wrong_type(self):
with pytest.raises(TypeError) as e:
_config.set_run_validators("False")
assert "'run' must be bool." == e.value.args[0]

def test_no_run_validators(self):
"""
The `no_run_validators` context manager disables running validators,
but only within its context.
"""
assert _config._run_validators is True
with _config.no_run_validators():
assert _config._run_validators is False
assert _config._run_validators is True

def test_no_run_validators_with_errors(self):
"""
Running validators is re-enabled even if an error is raised.
"""
assert _config._run_validators is True
with pytest.raises(ValueError):
with _config.no_run_validators():
assert _config._run_validators is False
raise ValueError("haha!")
assert _config._run_validators is True

0 comments on commit 8bf5cb8

Please sign in to comment.