Files
scikit-image/skimage/_shared/_warnings.py
T
Steven Silvester c0a0490eed Fix handling of multiple warnings and update tests
Fix handling of multiple warnings

Update all test __init__ files

Update segmentation pkg

Update the color pkg

Update the exposure pkg

Update the filters pkg

Update the io pkg

Update the measure pkg

Update morphology package

Restructure test setup function

Add expected_warnings to __all__

Update restoration pkg.

Remove explicit filter check since it is done elsewhere

Fix the image test helpers

Update the transform pkg

Fix util pkg

Update viewer pkg
2014-12-23 16:51:06 -06:00

106 lines
3.1 KiB
Python

__all__ = ['all_warnings', 'expected_warnings']
from contextlib import contextmanager
import sys
import warnings
import inspect
import re
@contextmanager
def all_warnings():
"""
Context for use in testing to ensure that all warnings are raised.
Examples
--------
>>> import warnings
>>> def foo():
... warnings.warn(RuntimeWarning("bar"))
We raise the warning once, while the warning filter is set to "once".
Hereafter, the warning is invisible, even with custom filters:
>>> with warnings.catch_warnings():
... warnings.simplefilter('once')
... foo()
We can now run ``foo()`` without a warning being raised:
>>> from numpy.testing import assert_warns
>>> foo()
To catch the warning, we call in the help of ``all_warnings``:
>>> with all_warnings():
... assert_warns(RuntimeWarning, foo)
"""
# Whenever a warning is triggered, Python adds a __warningregistry__
# member to the *calling* module. The exercize here is to find
# and eradicate all those breadcrumbs that were left lying around.
#
# We proceed by first searching all parent calling frames and explicitly
# clearing their warning registries (necessary for the doctests above to
# pass). Then, we search for all submodules of skimage and clear theirs
# as well (necessary for the skimage test suite to pass).
frame = inspect.currentframe()
if frame:
for f in inspect.getouterframes(frame):
f[0].f_locals['__warningregistry__'] = {}
del frame
for mod_name, mod in list(sys.modules.items()):
if 'six.moves' in mod_name:
continue
try:
mod.__warningregistry__.clear()
except AttributeError:
pass
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
yield w
@contextmanager
def expected_warnings(matching):
"""Context for use in testing to catch known warnings matching regexes
Parameters
----------
matching : list of strings or compiled regexes
Regexes for the desired warning to catch
Examples
--------
>>> from skimage import data, img_as_ubyte, img_as_float
>>> with expected_warnings(['precision loss']):
... d = img_as_ubyte(img_as_float(data.coins()))
Notes
-----
Uses `all_warnings` to ensure all warnings are raised.
Upon exiting, it checks the recorded warnings for the desired matching
string. Raises a warning if the match was not found or an Unexpected
warning is found.
"""
with all_warnings() as w:
yield w
remaining = [m for m in matching]
for warn in w:
found = False
for match in matching:
if re.search(match, str(warn.message)) is not None:
found = True
if match in remaining:
remaining.remove(match)
if not found:
raise ValueError('Unexpected warning: %s' % str(warn.message))
if len(remaining) > 0:
msg = 'No warning raised matching:\n%s' % '\n'.join(remaining)
raise ValueError(msg)