parametrize_from_file.error_or(*expected, globals=None, param='error', mock_factory=<class 'unittest.mock.MagicMock'>)

Return a schema function that will expect to be given either an error or the specified set of expected values.

  • expected (str) – Any test parameters that must be specified when an exception is not expected. These parameters will be replaced with mocks when an exception is expected.

  • globals (dict) – The global variables to use when building the error context manager, e.g. for evaluating the exception type. This can be any kind of mapping, including Namespace.

  • param (str) – The name of the test parameter specifying the expected exception.

  • mock_factory (Callable) – A no-argument callable that can be used to create mock expected values when an exception is expected.

The purpose of this schema is to make it easier to test functions that can raise exceptions. Towards this end, this schema understands two sets of parameters: one that defines an expected outcome when no exceptions are expected, and another that defines an expected exception. These parameter sets are mutually exclusive: you cannot specify both at once.

By default, exceptions are specified using the error parameter. (The name of this parameter can be changed via the param argument.) If this parameter is found, it will be processed by Namespace.error. That means: (i) it should match the format expected by that method and (ii) it will be converted into a context manager that can be used to detect whether the expected exception was in fact raised. All of the expected keys will be added to the output dictionary, and will be set to MagicMock objects. These mocks are pretty good at standing in for other objects, so if you need to do some mild processing on the expected values before performing the actual test, it will often just work. When it doesn’t, the error parameter will be truthy if an exception is expected and falsey otherwise, so you can use that information to skip this kind of processing as necessary.

If the error parameter is not given, the resulting output will contain an error key set to a no-op context manager. All of the expected keys will be passed through unchanged.

For more information, see the Exceptions tutorial.


This example is somewhat contrived, but it shows how to easily test a function that raises a custom exception for certain inputs.

>>> from parametrize_from_file import Namespace, error_or
>>> class DontGreet(Exception):
...     pass
>>> def greet(name):
...     if name == 'Bob':
...         raise DontGreet(name)
...     return f"Hello, {name}!"
>>> with_greet = Namespace(globals())
>>> schema = with_greet.error_or('expected')
>>> p1 = schema({
...         'given': 'Alice',
...         'expected': 'Hello, Alice!',
... })
>>> with p1['error']:
...    assert greet(p1['given']) == p1['expected']
>>> p2 = schema({
...         'given': 'Bob',
...         'error': {
...             'type': 'DontGreet',
...             'message': 'Bob',
...         },
... })
>>> with p2['error']:
...    assert greet(p2['given']) == p2['expected']

Note that the with block is the exact same for both assertions, even though one tests for an error and the other doesn’t. This is what makes error_or() useful for writing parametrized tests.