diff --git a/IPython/external/_numpy_testing_utils.py b/IPython/external/_numpy_testing_utils.py new file mode 100644 index 0000000..8bcbb05 --- /dev/null +++ b/IPython/external/_numpy_testing_utils.py @@ -0,0 +1,120 @@ +# IPython: modified copy of numpy.testing.utils, so numpy.testing.decorators +# works without numpy being installed. +""" +Utility function to facilitate testing. +""" + +import os +import sys +import re +import operator +import types +import warnings + +# The following two classes are copied from python 2.6 warnings module (context +# manager) +class WarningMessage(object): + + """ + Holds the result of a single showwarning() call. + + Notes + ----- + `WarningMessage` is copied from the Python 2.6 warnings module, + so it can be used in NumPy with older Python versions. + + """ + + _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", + "line") + + def __init__(self, message, category, filename, lineno, file=None, + line=None): + local_values = locals() + for attr in self._WARNING_DETAILS: + setattr(self, attr, local_values[attr]) + if category: + self._category_name = category.__name__ + else: + self._category_name = None + + def __str__(self): + return ("{message : %r, category : %r, filename : %r, lineno : %s, " + "line : %r}" % (self.message, self._category_name, + self.filename, self.lineno, self.line)) + +class WarningManager: + """ + A context manager that copies and restores the warnings filter upon + exiting the context. + + The 'record' argument specifies whether warnings should be captured by a + custom implementation of ``warnings.showwarning()`` and be appended to a + list returned by the context manager. Otherwise None is returned by the + context manager. The objects appended to the list are arguments whose + attributes mirror the arguments to ``showwarning()``. + + The 'module' argument is to specify an alternative module to the module + named 'warnings' and imported under that name. This argument is only useful + when testing the warnings module itself. + + Notes + ----- + `WarningManager` is a copy of the ``catch_warnings`` context manager + from the Python 2.6 warnings module, with slight modifications. + It is copied so it can be used in NumPy with older Python versions. + + """ + def __init__(self, record=False, module=None): + self._record = record + if module is None: + self._module = sys.modules['warnings'] + else: + self._module = module + self._entered = False + + def __enter__(self): + if self._entered: + raise RuntimeError("Cannot enter %r twice" % self) + self._entered = True + self._filters = self._module.filters + self._module.filters = self._filters[:] + self._showwarning = self._module.showwarning + if self._record: + log = [] + def showwarning(*args, **kwargs): + log.append(WarningMessage(*args, **kwargs)) + self._module.showwarning = showwarning + return log + else: + return None + + def __exit__(self): + if not self._entered: + raise RuntimeError("Cannot exit %r without entering first" % self) + self._module.filters = self._filters + self._module.showwarning = self._showwarning + +def assert_warns(warning_class, func, *args, **kw): + """Fail unless a warning of class warning_class is thrown by callable when + invoked with arguments args and keyword arguments kwargs. + + If a different type of warning is thrown, it will not be caught, and the + test case will be deemed to have suffered an error. + """ + + # XXX: once we may depend on python >= 2.6, this can be replaced by the + # warnings module context manager. + ctx = WarningManager(record=True) + l = ctx.__enter__() + warnings.simplefilter('always') + try: + func(*args, **kw) + if not len(l) > 0: + raise AssertionError("No warning raised when calling %s" + % func.__name__) + if not l[0].category is warning_class: + raise AssertionError("First warning for %s is not a " \ + "%s( is %s)" % (func.__name__, warning_class, l[0])) + finally: + ctx.__exit__() diff --git a/IPython/external/decorators.py b/IPython/external/decorators.py index 68335cc..6f457f1 100644 --- a/IPython/external/decorators.py +++ b/IPython/external/decorators.py @@ -16,8 +16,17 @@ function name, setup and teardown functions and so on - see import warnings import sys -from numpy.testing.utils import \ - WarningManager, WarningMessage +# IPython changes: make this work if numpy not available +# Original code: +#from numpy.testing.utils import \ +# WarningManager, WarningMessage +# Our version: +try: + from numpy.testing.utils import WarningManager, WarningMessage +except ImportError: + from _numpy_testing_utils import WarningManager, WarningMessage + +# End IPython changes def slow(t): """