diff --git a/skimage/util/__init__.py b/skimage/util/__init__.py index 5577e46b..07712230 100644 --- a/skimage/util/__init__.py +++ b/skimage/util/__init__.py @@ -7,6 +7,8 @@ from .arraypad import pad from ._regular_grid import regular_grid from .unique import unique_rows +from ._warnings import all_warnings + __all__ = ['img_as_float', 'img_as_int', diff --git a/skimage/util/_warnings.py b/skimage/util/_warnings.py new file mode 100644 index 00000000..f4bbf5c2 --- /dev/null +++ b/skimage/util/_warnings.py @@ -0,0 +1,60 @@ +__all__ = ['all_warnings'] + +from contextlib import contextmanager +import sys +import warnings +import inspect + +@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 in sys.modules.values(): + try: + mod.__warningregistry__.clear() + except AttributeError: + pass + + with warnings.catch_warnings(): + warnings.simplefilter("always") + yield