Repository: scipy/scipy
Pull request: TST: Warning cleanup
These includes some cleanups, especially, however, it (re)enables that warnings are actually tested for as errors during development.

This flushed quite a few errors on Py3k especially, that were only ignored/caught but not specifically with a filter. Some of these filters could be done a bit more nicely with an `assert_warns`, if you prefer that.

This is a start (and a big step) to close gh-7524, after this, the remainings things are probably even more straight forward.

Problem statement:
TST: Clean up "ignore" warnings
gh-5796 has a start (and example) for avoiding "ignore" warning filters, especially in the test suit. They are problematic due to a python issue (actually limited to python <3.4 or so), which means that ignoring them in one test, can sometimes lead to ignoring them in other places as well. Which is mostly annoying if you want to test for the same warning elsewhere (one thing where it bit me in numpy especially was `DeprecationWarnings`).

This is pretty straight forward, look at what gh-5796 does, then:

 1. Check for ignores, for example with `git grep "warn.*ignore"`
 2. Choose some file, and remove the filters (if you want, you can do the testing step here, to make sure they were actually needed, but sometimes it is system dependend
 3. Run the test suit  (EDIT: Warnings should now be errors in development versions, so nothing special needed).
 4. Clean up any new errors, new errors are not untypical, at least on python 2 (on python 3.5 or so I am not quite sure, maybe here they are already printed and will show up in 3. from the start).
     * I would suggest to try to be more specific then what they where, i.e. do not just use `DeprecationWarning`, add a bit of the warning message, so that one realizes new deprecation warnings affecting the same test (EDIT: Plus it might allow grepping for it in the future, etc.)
 5. Start again from 1. :)

Once scipy is all clean, I have a code test in numpy (that were based on some scipy stuff I think), to check that no new "ignore" filters are added. You could do similar things here.

Hints from issue discussion:
Thanks @seberg!
Labelled as easy-fix because it is indeed a straightforward task. It's quite a large one, but no need to tackle all of SciPy at once: if you want to do just one file or module, that'd be very welcome too.

Commit message: TST: test_stats fixup for NaNs

It seems I am not seeing them on my computer locally, maybe due to
a different numpy version or so.

Patch to review:
diff --git a/runtests.py b/runtests.py
index f2c8e35b9f3b..d506c1541773 100755
--- a/runtests.py
+++ b/runtests.py
@@ -266,7 +266,13 @@ def test(*a, **kw):
             extra_argv = extra_argv + tests[1:]
             kw['extra_argv'] = extra_argv
             from numpy.testing import Tester
-            return Tester(tests[0]).test(*a, **kw)
+            from scipy.version import version as __version__
+
+            if ".dev0" in __version__:
+                mode = "develop"
+            else:
+                mode = "release"
+            return Tester(tests[0], raise_warnings=mode).test(*a, **kw)
     else:
         __import__(PROJECT_MODULE)
         test = sys.modules[PROJECT_MODULE].test
diff --git a/scipy/__init__.py b/scipy/__init__.py
index 5dcba30173c3..7a3dab5a237c 100644
--- a/scipy/__init__.py
+++ b/scipy/__init__.py
@@ -127,6 +127,11 @@ def test(*a, **kw):
         kw['extra_argv'] = list(kw.get('extra_argv', [])) + underscore_paths
         return test._tester.test(*a, **kw)
 
-    test._tester = Tester()
+    if ".dev0" in __version__:
+        mode = "develop"
+    else:
+        mode = "release"
+    test._tester = Tester(raise_warnings=mode)
     test.__doc__ = test._tester.test.__doc__
     test.__test__ = False  # Prevent nose from treating test() as a test
+
diff --git a/scipy/interpolate/tests/test_fitpack2.py b/scipy/interpolate/tests/test_fitpack2.py
index ef038d562cdf..688226f82ed4 100644
--- a/scipy/interpolate/tests/test_fitpack2.py
+++ b/scipy/interpolate/tests/test_fitpack2.py
@@ -1,12 +1,11 @@
 # Created by Pearu Peterson, June 2003
 from __future__ import division, print_function, absolute_import
 
-import warnings
-
 import numpy as np
 from numpy.testing import (assert_equal, assert_almost_equal, assert_array_equal,
         assert_array_almost_equal, assert_allclose, assert_raises, TestCase,
         run_module_suite)
+from scipy._lib._numpy_compat import suppress_warnings
 from numpy import array, diff, linspace, meshgrid, ones, pi, shape
 from scipy.interpolate.fitpack import bisplrep, bisplev
 from scipy.interpolate.fitpack2 import (UnivariateSpline,
@@ -194,8 +193,10 @@ def test_linear_constant(self):
         s = 0.1
         tx = [1+s,3-s]
         ty = [1+s,3-s]
-        with warnings.catch_warnings(record=True):  # coefficients of the ...
+        with suppress_warnings() as sup:
+            r = sup.record(UserWarning, "\nThe coefficients of the spline")
             lut = LSQBivariateSpline(x,y,z,tx,ty,kx=1,ky=1)
+            assert_equal(len(r), 1)
 
         assert_almost_equal(lut(2,2), 3.)
 
@@ -206,9 +207,9 @@ def test_bilinearity(self):
         s = 0.1
         tx = [1+s,3-s]
         ty = [1+s,3-s]
-        with warnings.catch_warnings():
+        with suppress_warnings() as sup:
             # This seems to fail (ier=1, see ticket 1642).
-            warnings.simplefilter('ignore', UserWarning)
+            sup.filter(UserWarning, "\nThe coefficients of the spline")
             lut = LSQBivariateSpline(x,y,z,tx,ty,kx=1,ky=1)
 
         tx, ty = lut.get_knots()
@@ -232,8 +233,10 @@ def test_integral(self):
         s = 0.1
         tx = [1+s,3-s]
         ty = [1+s,3-s]
-        with warnings.catch_warnings(record=True):  # coefficients of the ...
-            lut = LSQBivariateSpline(x,y,z,tx,ty,kx=1,ky=1)
+        with suppress_warnings() as sup:
+            r = sup.record(UserWarning, "\nThe coefficients of the spline")
+            lut = LSQBivariateSpline(x, y, z, tx, ty, kx=1, ky=1)
+            assert_equal(len(r), 1)
         tx, ty = lut.get_knots()
         tz = lut(tx, ty)
         trpz = .25*(diff(tx)[:,None]*diff(ty)[None,:]
@@ -250,8 +253,10 @@ def test_empty_input(self):
         s = 0.1
         tx = [1+s,3-s]
         ty = [1+s,3-s]
-        with warnings.catch_warnings(record=True):  # coefficients of the ...
-            lut = LSQBivariateSpline(x,y,z,tx,ty,kx=1,ky=1)
+        with suppress_warnings() as sup:
+            r = sup.record(UserWarning, "\nThe coefficients of the spline")
+            lut = LSQBivariateSpline(x, y, z, tx, ty, kx=1, ky=1)
+            assert_equal(len(r), 1)
 
         assert_array_equal(lut([], []), np.zeros((0,0)))
         assert_array_equal(lut([], [], grid=False), np.zeros((0,)))
@@ -283,9 +288,9 @@ def test_integral(self):
         y = [1,2,3,1,2,3,1,2,3]
         z = array([0,7,8,3,4,7,1,3,4])
 
-        with warnings.catch_warnings():
+        with suppress_warnings() as sup:
             # This seems to fail (ier=1, see ticket 1642).
-            warnings.simplefilter('ignore', UserWarning)
+            sup.filter(UserWarning, "\nThe required storage space")
             lut = SmoothBivariateSpline(x, y, z, kx=1, ky=1, s=0)
 
         tx = [1,2,4]
diff --git a/scipy/io/matlab/tests/test_mio.py b/scipy/io/matlab/tests/test_mio.py
index 361ae1a3f41f..84438e985270 100644
--- a/scipy/io/matlab/tests/test_mio.py
+++ b/scipy/io/matlab/tests/test_mio.py
@@ -21,6 +21,7 @@
 from numpy.testing import (assert_array_equal, assert_array_almost_equal,
                            assert_equal, assert_raises, run_module_suite,
                            assert_)
+from scipy._lib._numpy_compat import suppress_warnings
 
 import numpy as np
 from numpy import array
@@ -1204,7 +1205,8 @@ def test_miuint32_compromise():
     assert_equal(res['an_array'], np.arange(10)[None, :])
     # mat file with miUINT32 for miINT32, with negative value
     filename = pjoin(test_data_path, 'bad_miuint32.mat')
-    with warnings.catch_warnings(record=True):  # Py3k ResourceWarning
+    with suppress_warnings() as sup:
+        sup.filter(message="unclosed file")  # Py3k ResourceWarning
         assert_raises(ValueError, loadmat, filename)
 
 
@@ -1215,7 +1217,8 @@ def test_miutf8_for_miint8_compromise():
     assert_equal(res['array_name'], [[1]])
     # mat file with non-ascii utf8 name raises error
     filename = pjoin(test_data_path, 'bad_miutf8_array_name.mat')
-    with warnings.catch_warnings(record=True):  # Py3k ResourceWarning
+    with suppress_warnings() as sup:
+        sup.filter(message="unclosed file")  # Py3k ResourceWarning
         assert_raises(ValueError, loadmat, filename)
 
 
diff --git a/scipy/misc/tests/test_pilutil.py b/scipy/misc/tests/test_pilutil.py
index f18bb6cd28f4..55aa989032ad 100644
--- a/scipy/misc/tests/test_pilutil.py
+++ b/scipy/misc/tests/test_pilutil.py
@@ -4,13 +4,12 @@
 import tempfile
 import shutil
 import numpy as np
-import warnings
 import glob
 
 from numpy.testing import (assert_equal, dec, decorate_methods,
                            TestCase, run_module_suite, assert_allclose,
                            assert_array_equal, assert_raises)
-
+from scipy._lib._numpy_compat import suppress_warnings
 from scipy import misc
 from numpy.ma.testutils import assert_mask_equal
 
@@ -116,19 +115,23 @@ def test_bytescale_low_equals_high(self):
     def test_imsave(self):
         picdir = os.path.join(datapath, "data")
         for png in glob.iglob(picdir + "/*.png"):
-            with warnings.catch_warnings(record=True):  # PIL ResourceWarning
+            with suppress_warnings() as sup:
+                # PIL causes a Py3k ResourceWarning
+                sup.filter(message="unclosed file")
                 img = misc.imread(png)
             tmpdir = tempfile.mkdtemp()
             try:
                 fn1 = os.path.join(tmpdir, 'test.png')
                 fn2 = os.path.join(tmpdir, 'testimg')
-                # PIL ResourceWarning
-                with warnings.catch_warnings(record=True):
+                with suppress_warnings() as sup:
+                    # PIL causes a Py3k ResourceWarning
+                    sup.filter(message="unclosed file")
                     misc.imsave(fn1, img)
                     misc.imsave(fn2, img, 'PNG')
 
-                # PIL ResourceWarning
-                with warnings.catch_warnings(record=True):
+                with suppress_warnings() as sup:
+                    # PIL causes a Py3k ResourceWarning
+                    sup.filter(message="unclosed file")
                     data1 = misc.imread(fn1)
                     data2 = misc.imread(fn2)
                 assert_allclose(data1, img)
diff --git a/scipy/ndimage/tests/test_io.py b/scipy/ndimage/tests/test_io.py
index 91f793223471..fd12fb2c75c9 100644
--- a/scipy/ndimage/tests/test_io.py
+++ b/scipy/ndimage/tests/test_io.py
@@ -1,10 +1,10 @@
 from __future__ import division, print_function, absolute_import
 
 from numpy.testing import assert_array_equal, dec, run_module_suite
+from scipy._lib._numpy_compat import suppress_warnings
 import scipy.ndimage as ndi
 
 import os
-import warnings
 
 try:
     from PIL import Image
@@ -16,11 +16,15 @@
 @dec.skipif(pil_missing, msg="The Python Image Library could not be found.")
 def test_imread():
     lp = os.path.join(os.path.dirname(__file__), 'dots.png')
-    with warnings.catch_warnings(record=True):  # Py3k ResourceWarning
+    with suppress_warnings() as sup:
+        # PIL causes a Py3k ResourceWarning
+        sup.filter(message="unclosed file")
         img = ndi.imread(lp, mode="RGB")
     assert_array_equal(img.shape, (300, 420, 3))
 
-    with warnings.catch_warnings(record=True):  # PIL ResourceWarning
+    with suppress_warnings() as sup:
+        # PIL causes a Py3k ResourceWarning
+        sup.filter(message="unclosed file")
         img = ndi.imread(lp, flatten=True)
     assert_array_equal(img.shape, (300, 420))
 
diff --git a/scipy/signal/tests/test_windows.py b/scipy/signal/tests/test_windows.py
index 12db14d823b2..0d23db0d6033 100644
--- a/scipy/signal/tests/test_windows.py
+++ b/scipy/signal/tests/test_windows.py
@@ -1,11 +1,11 @@
 from __future__ import division, print_function, absolute_import
 
-import warnings
 import numpy as np
 from numpy import array
 from numpy.testing import (assert_array_almost_equal, assert_array_equal,
                            run_module_suite, assert_raises, assert_allclose,
                            assert_equal, assert_, assert_array_less)
+from scipy._lib._numpy_compat import suppress_warnings
 from scipy import signal, fftpack
 
 
@@ -149,8 +149,8 @@ def test_basic(self):
 class TestChebWin(object):
 
     def test_basic(self):
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", UserWarning)
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             assert_allclose(signal.chebwin(6, 100),
                             [0.1046401879356917, 0.5075781475823447, 1.0, 1.0,
                              0.5075781475823447, 0.1046401879356917])
@@ -171,14 +171,14 @@ def test_basic(self):
                              0.5190521247588651])
 
     def test_cheb_odd_high_attenuation(self):
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", UserWarning)
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             cheb_odd = signal.chebwin(53, at=-40)
         assert_array_almost_equal(cheb_odd, cheb_odd_true, decimal=4)
 
     def test_cheb_even_high_attenuation(self):
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", UserWarning)
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             cheb_even = signal.chebwin(54, at=40)
         assert_array_almost_equal(cheb_even, cheb_even_true, decimal=4)
 
@@ -186,8 +186,8 @@ def test_cheb_odd_low_attenuation(self):
         cheb_odd_low_at_true = array([1.000000, 0.519052, 0.586405,
                                       0.610151, 0.586405, 0.519052,
                                       1.000000])
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", UserWarning)
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             cheb_odd = signal.chebwin(7, at=10)
         assert_array_almost_equal(cheb_odd, cheb_odd_low_at_true, decimal=4)
 
@@ -195,8 +195,8 @@ def test_cheb_even_low_attenuation(self):
         cheb_even_low_at_true = array([1.000000, 0.451924, 0.51027,
                                        0.541338, 0.541338, 0.51027,
                                        0.451924, 1.000000])
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", UserWarning)
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             cheb_even = signal.chebwin(8, at=-10)
         assert_array_almost_equal(cheb_even, cheb_even_low_at_true, decimal=4)
 
@@ -445,14 +445,14 @@ def test_boxcar(self):
         assert_array_equal(w, np.ones_like(w))
 
     def test_cheb_odd(self):
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", UserWarning)
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             w = signal.get_window(('chebwin', -40), 53, fftbins=False)
         assert_array_almost_equal(w, cheb_odd_true, decimal=4)
 
     def test_cheb_even(self):
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", UserWarning)
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             w = signal.get_window(('chebwin', 40), 54, fftbins=False)
         assert_array_almost_equal(w, cheb_even_true, decimal=4)
 
@@ -481,8 +481,8 @@ def test_array_as_window(self):
 def test_windowfunc_basics():
     for window_name, params in window_funcs:
         window = getattr(signal, window_name)
-        with warnings.catch_warnings(record=True):  # window is not suitable...
-
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "This window is not suitable")
             # Check symmetry for odd and even lengths
             w1 = window(8, *params, sym=True)
             w2 = window(7, *params, sym=False)
diff --git a/scipy/special/tests/test_ellip_harm.py b/scipy/special/tests/test_ellip_harm.py
index 7266eb744d83..24c55f4e7d2b 100644
--- a/scipy/special/tests/test_ellip_harm.py
+++ b/scipy/special/tests/test_ellip_harm.py
@@ -5,11 +5,10 @@
 
 from __future__ import division, print_function, absolute_import
 
-import warnings
-
 import numpy as np
 from numpy.testing import (assert_equal, assert_almost_equal, assert_allclose,
                            assert_, run_module_suite)
+from scipy._lib._numpy_compat import suppress_warnings
 from scipy.special._testutils import assert_func_equal
 from scipy.special import ellip_harm, ellip_harm_2, ellip_normal
 from scipy.integrate import IntegrationWarning
@@ -56,8 +55,9 @@ def potential(lambda1, mu1, nu1, lambda2, mu2, nu2, h2, k2):
         (120, sqrt(16), 3.2, 21, sqrt(11), 2.9, 11, 20),
        ]
 
-    with warnings.catch_warnings():
-        warnings.simplefilter("ignore", category=IntegrationWarning)
+    with suppress_warnings() as sup:
+        sup.filter(IntegrationWarning, "The occurrence of roundoff error")
+        sup.filter(IntegrationWarning, "The maximum number of subdivisions")
 
         for p in pts:
             err_msg = repr(p)
@@ -162,7 +162,8 @@ def ellip_normal_known(h2, k2, n, p):
         for p in range(1, 2*n+2):
             points.append((h2, k2, n*np.ones(h2.size), p*np.ones(h2.size)))
     points = np.array(points)
-    with warnings.catch_warnings(record=True):  # occurrence of roundoff ...
+    with suppress_warnings() as sup:
+        sup.filter(IntegrationWarning, "The occurrence of roundoff error")
         assert_func_equal(ellip_normal, ellip_normal_known, points, rtol=1e-12)
 
 
@@ -174,7 +175,8 @@ def I1(h2, k2, s):
         ellip_harm_2(h2, k2, 1, 3, s)/(3 * ellip_harm(h2, k2, 1, 3, s)))
         return res
 
-    with warnings.catch_warnings(record=True):  # occurrence of roundoff ...
+    with suppress_warnings() as sup:
+        sup.filter(IntegrationWarning, "The occurrence of roundoff error")
         assert_almost_equal(I1(5, 8, 10), 1/(10*sqrt((100-5)*(100-8))))
 
         # Values produced by code from arXiv:1204.0267
diff --git a/scipy/stats/tests/test_morestats.py b/scipy/stats/tests/test_morestats.py
index 4133b07ca286..e240a764263a 100644
--- a/scipy/stats/tests/test_morestats.py
+++ b/scipy/stats/tests/test_morestats.py
@@ -11,7 +11,7 @@
 from numpy.testing import (TestCase, run_module_suite, assert_array_equal,
     assert_almost_equal, assert_array_less, assert_array_almost_equal,
     assert_raises, assert_, assert_allclose, assert_equal, dec, assert_warns)
-
+from scipy._lib._numpy_compat import suppress_warnings
 from scipy import stats
 from common_tests import check_named_results
 
@@ -266,8 +266,8 @@ def test_example1a(self):
         t4 = np.array([34.0, 34.8, 34.8, 35.4, 37.2, 37.8, 41.2, 42.8])
         assert_warns(UserWarning, stats.anderson_ksamp, (t1, t2, t3, t4),
                      midrank=False)
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', message='approximate p-value')
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, message='approximate p-value')
             Tk, tm, p = stats.anderson_ksamp((t1, t2, t3, t4), midrank=False)
 
         assert_almost_equal(Tk, 4.449, 3)
@@ -284,8 +284,8 @@ def test_example1b(self):
         t2 = np.array([39.2, 39.3, 39.7, 41.4, 41.8, 42.9, 43.3, 45.8])
         t3 = np.array([34.0, 35.0, 39.0, 40.0, 43.0, 43.0, 44.0, 45.0])
         t4 = np.array([34.0, 34.8, 34.8, 35.4, 37.2, 37.8, 41.2, 42.8])
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', message='approximate p-value')
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, message='approximate p-value')
             Tk, tm, p = stats.anderson_ksamp((t1, t2, t3, t4), midrank=True)
 
         assert_almost_equal(Tk, 4.480, 3)
@@ -316,8 +316,8 @@ def test_example2a(self):
         t13 = [487, 18, 100, 7, 98, 5, 85, 91, 43, 230, 3, 130]
         t14 = [102, 209, 14, 57, 54, 32, 67, 59, 134, 152, 27, 14, 230, 66,
                61, 34]
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', message='approximate p-value')
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, message='approximate p-value')
             Tk, tm, p = stats.anderson_ksamp((t1, t2, t3, t4, t5, t6, t7, t8,
                                               t9, t10, t11, t12, t13, t14),
                                              midrank=False)
@@ -349,8 +349,8 @@ def test_example2b(self):
         t13 = [487, 18, 100, 7, 98, 5, 85, 91, 43, 230, 3, 130]
         t14 = [102, 209, 14, 57, 54, 32, 67, 59, 134, 152, 27, 14, 230, 66,
                61, 34]
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', message='approximate p-value')
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, message='approximate p-value')
             Tk, tm, p = stats.anderson_ksamp((t1, t2, t3, t4, t5, t6, t7, t8,
                                               t9, t10, t11, t12, t13, t14),
                                              midrank=True)
@@ -380,8 +380,8 @@ def test_result_attributes(self):
         t3 = np.array([34.0, 35.0, 39.0, 40.0, 43.0, 43.0, 44.0, 45.0])
         t4 = np.array([34.0, 34.8, 34.8, 35.4, 37.2, 37.8, 41.2, 42.8])
 
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', message='approximate p-value')
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, message='approximate p-value')
             res = stats.anderson_ksamp((t1, t2, t3, t4), midrank=False)
 
         attributes = ('statistic', 'critical_values', 'significance_level')
@@ -393,7 +393,8 @@ class TestAnsari(TestCase):
     def test_small(self):
         x = [1, 2, 3, 3, 4]
         y = [3, 2, 6, 1, 6, 1, 4, 1]
-        with warnings.catch_warnings(record=True):  # Ties preclude use ...
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "Ties preclude use of exact statistic.")
             W, pval = stats.ansari(x, y)
         assert_almost_equal(W, 23.5, 11)
         assert_almost_equal(pval, 0.13499256881897437, 11)
@@ -405,9 +406,8 @@ def test_approx(self):
                            100, 96, 108, 103, 104, 114, 114, 113, 108,
                            106, 99))
 
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore',
-                        message="Ties preclude use of exact statistic.")
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "Ties preclude use of exact statistic.")
             W, pval = stats.ansari(ramsay, parekh)
 
         assert_almost_equal(W, 185.5, 11)
@@ -425,7 +425,8 @@ def test_bad_arg(self):
     def test_result_attributes(self):
         x = [1, 2, 3, 3, 4]
         y = [3, 2, 6, 1, 6, 1, 4, 1]
-        with warnings.catch_warnings(record=True):  # Ties preclude use ...
+        with suppress_warnings() as sup:
+            sup.filter(UserWarning, "Ties preclude use of exact statistic.")
             res = stats.ansari(x, y)
         attributes = ('statistic', 'pvalue')
         check_named_results(res, attributes)
diff --git a/scipy/stats/tests/test_stats.py b/scipy/stats/tests/test_stats.py
index a2881964c96f..ca743fe9305c 100644
--- a/scipy/stats/tests/test_stats.py
+++ b/scipy/stats/tests/test_stats.py
@@ -18,7 +18,7 @@
                            assert_array_equal, assert_approx_equal,
                            assert_raises, run_module_suite, assert_allclose,
                            dec)
-from scipy._lib._numpy_compat import assert_raises_regex
+from scipy._lib._numpy_compat import assert_raises_regex, suppress_warnings
 import numpy.ma.testutils as mat
 from numpy import array, arange, float32, float64, power
 import numpy as np
@@ -553,8 +553,7 @@ def test_spearmanr():
     check_named_results(res, attributes)
 
     # with only ties in one or both inputs
-    with warnings.catch_warnings():
-        warnings.simplefilter("ignore", RuntimeWarning)
+    with np.errstate(invalid="ignore"):
         assert_equal(stats.spearmanr([2,2,2], [2,2,2]), (np.nan, np.nan))
         assert_equal(stats.spearmanr([2,0,2], [2,2,2]), (np.nan, np.nan))
         assert_equal(stats.spearmanr([2,2,2], [2,0,2]), (np.nan, np.nan))
@@ -997,8 +996,7 @@ def test_nan_input(self):
         x = np.arange(10.)
         x[9] = np.nan
 
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", RuntimeWarning)
+        with np.errstate(invalid="ignore"):
             assert_array_equal(stats.linregress(x, x),
                                (np.nan, np.nan, np.nan, np.nan, np.nan))
 
@@ -1054,8 +1052,9 @@ def test_simple(self):
                                           -1.2222222222222223, 0.44444444444444448, 0)),
                        )
         for inputs, expected_results in basic_tests:
-            with warnings.catch_warnings():
-                warnings.simplefilter("ignore", DeprecationWarning)
+            with suppress_warnings() as sup:
+                sup.filter(DeprecationWarning,
+                           message="`histogram` is deprecated")
                 given_results = stats.histogram(inputs)
 
             assert_array_almost_equal(expected_results[0], given_results[0],
@@ -1065,8 +1064,8 @@ def test_simple(self):
                                     decimal=2)
 
     def test_empty(self):
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", DeprecationWarning)
+        with suppress_warnings() as sup:
+            sup.filter(DeprecationWarning, message="`histogram` is deprecated")
             res = stats.histogram([])
 
         # expected values
@@ -1096,8 +1095,9 @@ def test_reduced_bins(self):
                                           -1.5, 1.0, 0)),
                        )
         for inputs, expected_results in basic_tests:
-            with warnings.catch_warnings():
-                warnings.simplefilter("ignore", DeprecationWarning)
+            with suppress_warnings() as sup:
+                sup.filter(DeprecationWarning,
+                           message="`histogram` is deprecated")
                 given_results = stats.histogram(inputs, numbins=5)
 
             assert_array_almost_equal(expected_results[0], given_results[0],
@@ -1134,8 +1134,9 @@ def test_increased_bins(self):
                                           -1.1052631578947367, 0.21052631578947367, 0)),
                        )
         for inputs, expected_results in basic_tests:
-            with warnings.catch_warnings():
-                warnings.simplefilter("ignore", DeprecationWarning)
+            with suppress_warnings() as sup:
+                sup.filter(DeprecationWarning,
+                           message="`histogram` is deprecated")
                 given_results = stats.histogram(inputs, numbins=20)
 
             assert_array_almost_equal(expected_results[0], given_results[0],
@@ -1145,8 +1146,8 @@ def test_increased_bins(self):
                                     decimal=2)
 
     def test_histogram_result_attributes(self):
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", DeprecationWarning)
+        with suppress_warnings() as sup:
+            sup.filter(DeprecationWarning, message="`histogram` is deprecated")
             res = stats.histogram(self.low_range, numbins=20)
 
         attributes = ('count', 'lowerlimit', 'binsize', 'extrapoints')
@@ -1464,9 +1465,12 @@ def test_axes(self):
 
     def test_strings(self):
         data1 = ['rain', 'showers', 'showers']
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", RuntimeWarning)
+
+        with suppress_warnings() as sup:
+            r = sup.record(RuntimeWarning, ".*checked for nan values")
             vals = stats.mode(data1)
+            assert_equal(len(r), 1)
+
         assert_equal(vals[0][0], 'showers')
         assert_equal(vals[1][0], 2)
 
@@ -1475,9 +1479,10 @@ def test_mixed_objects(self):
         objects = [10, True, np.nan, 'hello', 10]
         arr = np.empty((5,), dtype=object)
         arr[:] = objects
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", RuntimeWarning)
+        with suppress_warnings() as sup:
+            r = sup.record(RuntimeWarning, ".*checked for nan values")
             vals = stats.mode(arr)
+            assert_equal(len(r), 1)
         assert_equal(vals[0][0], 10)
         assert_equal(vals[1][0], 2)
 
@@ -1505,9 +1510,10 @@ def __hash__(self):
         arr[:] = points
         assert_(len(set(points)) == 4)
         assert_equal(np.unique(arr).shape, (4,))
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=RuntimeWarning)
+        with suppress_warnings() as sup:
+            r = sup.record(RuntimeWarning, ".*checked for nan values")
             vals = stats.mode(arr)
+            assert_equal(len(r), 1)
 
         assert_equal(vals[0][0], Point(2))
         assert_equal(vals[1][0], 4)
@@ -1543,8 +1549,8 @@ def test_signaltonoise(self):
 
         # y = stats.signaltonoise(self.shoes[0])
         # assert_approx_equal(y,4.5709967)
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", DeprecationWarning)
+        with suppress_warnings() as sup:
+            sup.filter(DeprecationWarning, "`signaltonoise` is deprecated")
             y = stats.signaltonoise(self.testcase)
         assert_approx_equal(y, 2.236067977)
 
@@ -1554,8 +1560,8 @@ def test_sem(self):
 
         # y = stats.sem(self.shoes[0])
         # assert_approx_equal(y,0.775177399)
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=RuntimeWarning)
+        with suppress_warnings() as sup, np.errstate(invalid="ignore"):
+            sup.filter(RuntimeWarning, "Degrees of freedom <= 0 for slice")
             y = stats.sem(self.scalar_testcase)
         assert_(np.isnan(y))
 
@@ -2201,8 +2207,8 @@ def test_moment_accuracy(self):
 class TestThreshold(TestCase):
     def test_basic(self):
         a = [-1, 2, 3, 4, 5, -1, -2]
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=DeprecationWarning)
+        with suppress_warnings() as sup:
+            sup.filter(DeprecationWarning, "`threshold` is deprecated")
             assert_array_equal(stats.threshold(a), a)
             assert_array_equal(stats.threshold(a, 3, None, 0),
                                [0, 0, 3, 4, 5, 0, 0])
@@ -2225,8 +2231,8 @@ class TestStudentTest(TestCase):
     P2_0 = 0.2254033
 
     def test_onesample(self):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=RuntimeWarning)
+        with suppress_warnings() as sup, np.errstate(invalid="ignore"):
+            sup.filter(RuntimeWarning, "Degrees of freedom <= 0 for slice")
             t, p = stats.ttest_1samp(4., 3.)
         assert_(np.isnan(t))
         assert_(np.isnan(p))
@@ -2259,8 +2265,7 @@ def test_onesample(self):
         np.random.seed(7654567)
         x = stats.norm.rvs(loc=5, scale=10, size=51)
         x[50] = np.nan
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=RuntimeWarning)
+        with np.errstate(invalid="ignore"):
             assert_array_equal(stats.ttest_1samp(x, 5.0), (np.nan, np.nan))
 
             assert_array_almost_equal(stats.ttest_1samp(x, 5.0, nan_policy='omit'),
@@ -2428,16 +2433,20 @@ def check_power_divergence(self, f_obs, f_exp, ddof, axis, lambda_,
         else:
             b = np.broadcast(f_obs, f_exp)
             num_obs = b.shape[axis]
-        stat, p = stats.power_divergence(f_obs=f_obs, f_exp=f_exp, ddof=ddof,
-                                         axis=axis, lambda_=lambda_)
-        assert_allclose(stat, expected_stat)
-
-        if lambda_ == 1 or lambda_ == "pearson":
-            # Also test stats.chisquare.
-            stat, p = stats.chisquare(f_obs=f_obs, f_exp=f_exp, ddof=ddof,
-                                      axis=axis)
+
+        with suppress_warnings() as sup:
+            sup.filter(RuntimeWarning, "Mean of empty slice")
+            stat, p = stats.power_divergence(
+                                f_obs=f_obs, f_exp=f_exp, ddof=ddof,
+                                axis=axis, lambda_=lambda_)
             assert_allclose(stat, expected_stat)
 
+            if lambda_ == 1 or lambda_ == "pearson":
+                # Also test stats.chisquare.
+                stat, p = stats.chisquare(f_obs=f_obs, f_exp=f_exp, ddof=ddof,
+                                          axis=axis)
+                assert_allclose(stat, expected_stat)
+
         ddof = np.asarray(ddof)
         expected_p = stats.distributions.chi2.sf(expected_stat,
                                                  num_obs - 1 - ddof)
@@ -2548,7 +2557,6 @@ def test_ddof_broadcasting(self):
 
     def test_empty_cases(self):
         with warnings.catch_warnings():
-            warnings.simplefilter("ignore", RuntimeWarning)
             for case in power_div_empty_cases:
                 yield (self.check_power_divergence,
                        case.f_obs, case.f_exp, case.ddof, case.axis,
@@ -2623,8 +2631,8 @@ def test_chisquare_masked_arrays():
     # Empty arrays:
     # A data set with length 0 returns a masked scalar.
     with np.errstate(invalid='ignore'):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore')
+        with suppress_warnings() as sup:
+            sup.filter(RuntimeWarning, "Mean of empty slice")
             chisq, p = stats.chisquare(np.ma.array([]))
     assert_(isinstance(chisq, np.ma.MaskedArray))
     assert_equal(chisq.shape, ())
@@ -2641,8 +2649,8 @@ def test_chisquare_masked_arrays():
     # empty3.T is an array containing 3 data sets, each with length 0,
     # so an array of size (3,) is returned, with all values masked.
     with np.errstate(invalid='ignore'):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore')
+        with suppress_warnings() as sup:
+            sup.filter(RuntimeWarning, "Mean of empty slice")
             chisq, p = stats.chisquare(empty3.T)
 
     assert_(isinstance(chisq, np.ma.MaskedArray))
@@ -2844,8 +2852,8 @@ def test_ttest_rel():
     assert_array_almost_equal([t,p],tpr)
 
     # test scalars
-    with warnings.catch_warnings():
-        warnings.filterwarnings('ignore', category=RuntimeWarning)
+    with suppress_warnings() as sup, np.errstate(invalid="ignore"):
+        sup.filter(RuntimeWarning, "Degrees of freedom <= 0 for slice")
         t, p = stats.ttest_rel(4., 3.)
     assert_(np.isnan(t))
     assert_(np.isnan(p))
@@ -2875,28 +2883,25 @@ def test_ttest_rel():
     y = (stats.norm.rvs(loc=5, scale=10, size=501) +
          stats.norm.rvs(scale=0.2, size=501))
     y[500] = np.nan
-    with warnings.catch_warnings():
-        warnings.filterwarnings('ignore', category=RuntimeWarning)
+
+    with np.errstate(invalid="ignore"):
         assert_array_equal(stats.ttest_rel(x, x), (np.nan, np.nan))
 
-        assert_array_almost_equal(stats.ttest_rel(x, y, nan_policy='omit'),
-                                  (0.25299925303978066, 0.8003729814201519))
-        assert_raises(ValueError, stats.ttest_rel, x, y, nan_policy='raise')
-        assert_raises(ValueError, stats.ttest_rel, x, y, nan_policy='foobar')
+    assert_array_almost_equal(stats.ttest_rel(x, y, nan_policy='omit'),
+                              (0.25299925303978066, 0.8003729814201519))
+    assert_raises(ValueError, stats.ttest_rel, x, y, nan_policy='raise')
+    assert_raises(ValueError, stats.ttest_rel, x, y, nan_policy='foobar')
 
-        # test zero division problem
-        t, p = stats.ttest_rel([0, 0, 0], [1, 1, 1])
-        assert_equal((np.abs(t), p), (np.inf, 0))
+    # test zero division problem
+    t, p = stats.ttest_rel([0, 0, 0], [1, 1, 1])
+    assert_equal((np.abs(t), p), (np.inf, 0))
+    with np.errstate(invalid="ignore"):
         assert_equal(stats.ttest_rel([0, 0, 0], [0, 0, 0]), (np.nan, np.nan))
 
-    olderr = np.seterr(all='ignore')
-    try:
         # check that nan in input array result in nan output
         anan = np.array([[1, np.nan], [-1, 1]])
         assert_equal(stats.ttest_rel(anan, np.zeros((2, 2))),
                      ([0, np.nan], [1, np.nan]))
-    finally:
-        np.seterr(**olderr)
 
     # test incorrect input shape raise an error
     x = np.arange(24)
@@ -2964,8 +2969,8 @@ def test_ttest_ind():
                               [t, p])
 
     # test scalars
-    with warnings.catch_warnings():
-        warnings.filterwarnings('ignore', category=RuntimeWarning)
+    with suppress_warnings() as sup, np.errstate(invalid="ignore"):
+        sup.filter(RuntimeWarning, "Degrees of freedom <= 0 for slice")
         t, p = stats.ttest_ind(4., 3.)
     assert_(np.isnan(t))
     assert_(np.isnan(p))
@@ -2989,28 +2994,25 @@ def test_ttest_ind():
     x[500] = np.nan
     y = stats.norm.rvs(loc=5, scale=10, size=500)
 
-    with warnings.catch_warnings():
-        warnings.filterwarnings('ignore', category=RuntimeWarning)
+    with np.errstate(invalid="ignore"):
         assert_array_equal(stats.ttest_ind(x, y), (np.nan, np.nan))
 
-        assert_array_almost_equal(stats.ttest_ind(x, y, nan_policy='omit'),
-                                  (0.24779670949091914, 0.80434267337517906))
-        assert_raises(ValueError, stats.ttest_ind, x, y, nan_policy='raise')
-        assert_raises(ValueError, stats.ttest_ind, x, y, nan_policy='foobar')
+    assert_array_almost_equal(stats.ttest_ind(x, y, nan_policy='omit'),
+                              (0.24779670949091914, 0.80434267337517906))
+    assert_raises(ValueError, stats.ttest_ind, x, y, nan_policy='raise')
+    assert_raises(ValueError, stats.ttest_ind, x, y, nan_policy='foobar')
 
-        # test zero division problem
-        t, p = stats.ttest_ind([0, 0, 0], [1, 1, 1])
-        assert_equal((np.abs(t), p), (np.inf, 0))
+    # test zero division problem
+    t, p = stats.ttest_ind([0, 0, 0], [1, 1, 1])
+    assert_equal((np.abs(t), p), (np.inf, 0))
+    
+    with np.errstate(invalid="ignore"):
         assert_equal(stats.ttest_ind([0, 0, 0], [0, 0, 0]), (np.nan, np.nan))
 
-    olderr = np.seterr(all='ignore')
-    try:
         # check that nan in input array result in nan output
         anan = np.array([[1, np.nan], [-1, 1]])
         assert_equal(stats.ttest_ind(anan, np.zeros((2, 2))),
                      ([0, np.nan], [1, np.nan]))
-    finally:
-        np.seterr(**olderr)
 
 
 def test_ttest_ind_with_uneq_var():
@@ -3107,21 +3109,17 @@ def test_ttest_ind_with_uneq_var():
     assert_equal(t.shape, (3, 2))
 
     # test zero division problem
-    with warnings.catch_warnings():
-        warnings.filterwarnings('ignore', category=RuntimeWarning)
-        t, p = stats.ttest_ind([0, 0, 0], [1, 1, 1], equal_var=False)
-        assert_equal((np.abs(t), p), (np.inf, 0))
+    t, p = stats.ttest_ind([0, 0, 0], [1, 1, 1], equal_var=False)
+    assert_equal((np.abs(t), p), (np.inf, 0))
+    with np.errstate(all='ignore'):
         assert_equal(stats.ttest_ind([0, 0, 0], [0, 0, 0], equal_var=False),
                      (np.nan, np.nan))
 
-    olderr = np.seterr(all='ignore')
-    try:
         # check that nan in input array result in nan output
         anan = np.array([[1, np.nan], [-1, 1]])
         assert_equal(stats.ttest_ind(anan, np.zeros((2, 2)), equal_var=False),
                      ([0, np.nan], [1, np.nan]))
-    finally:
-        np.seterr(**olderr)
+
 
 def test_ttest_ind_nan_2nd_arg():
     # regression test for gh-6134: nans in the second arg were not handled
@@ -3180,25 +3178,21 @@ def test_ttest_1samp_new():
     assert_equal(t1.shape, (n1,n2))
 
     # test zero division problem
-    with warnings.catch_warnings():
-        warnings.filterwarnings('ignore', category=RuntimeWarning)
-        t, p = stats.ttest_1samp([0, 0, 0], 1)
-        assert_equal((np.abs(t), p), (np.inf, 0))
+    t, p = stats.ttest_1samp([0, 0, 0], 1)
+    assert_equal((np.abs(t), p), (np.inf, 0))
+
+    with np.errstate(all='ignore'):
         assert_equal(stats.ttest_1samp([0, 0, 0], 0), (np.nan, np.nan))
 
-    olderr = np.seterr(all='ignore')
-    try:
         # check that nan in input array result in nan output
         anan = np.array([[1, np.nan],[-1, 1]])
         assert_equal(stats.ttest_1samp(anan, 0), ([0, np.nan], [1, np.nan]))
-    finally:
-        np.seterr(**olderr)
 
 
 class TestDescribe(TestCase):
     def test_describe_scalar(self):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=RuntimeWarning)
+        with suppress_warnings() as sup, np.errstate(invalid="ignore"):
+            sup.filter(RuntimeWarning, "Degrees of freedom <= 0 for slice")
             n, mm, m, v, sk, kurt = stats.describe(4.)
         assert_equal(n, 1)
         assert_equal(mm, (4.0, 4.0))
@@ -3321,17 +3315,20 @@ def test_normalitytests():
 
     x = np.arange(10.)
     x[9] = np.nan
-    assert_array_equal(stats.skewtest(x), (np.nan, np.nan))
+    with np.errstate(invalid="ignore"):
+        assert_array_equal(stats.skewtest(x), (np.nan, np.nan))
 
     expected = (1.0184643553962129, 0.30845733195153502)
     assert_array_almost_equal(stats.skewtest(x, nan_policy='omit'), expected)
 
-    assert_raises(ValueError, stats.skewtest, x, nan_policy='raise')
+    with np.errstate(all='ignore'):
+        assert_raises(ValueError, stats.skewtest, x, nan_policy='raise')
     assert_raises(ValueError, stats.skewtest, x, nan_policy='foobar')
 
     x = np.arange(30.)
     x[29] = np.nan
-    assert_array_equal(stats.kurtosistest(x), (np.nan, np.nan))
+    with np.errstate(all='ignore'):
+        assert_array_equal(stats.kurtosistest(x), (np.nan, np.nan))
 
     expected = (-2.2683547379505273, 0.023307594135872967)
     assert_array_almost_equal(stats.kurtosistest(x, nan_policy='omit'),
@@ -3340,7 +3337,8 @@ def test_normalitytests():
     assert_raises(ValueError, stats.kurtosistest, x, nan_policy='raise')
     assert_raises(ValueError, stats.kurtosistest, x, nan_policy='foobar')
 
-    assert_array_equal(stats.normaltest(x), (np.nan, np.nan))
+    with np.errstate(all='ignore'):
+        assert_array_equal(stats.normaltest(x), (np.nan, np.nan))
 
     expected = (6.2260409514287449, 0.04446644248650191)
     assert_array_almost_equal(stats.normaltest(x, nan_policy='omit'), expected)
@@ -3442,8 +3440,9 @@ def test_mannwhitneyu_two_sided(self):
 
     def test_mannwhitneyu_default(self):
         # The default value for alternative is None
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", DeprecationWarning)
+        with suppress_warnings() as sup:
+            sup.filter(DeprecationWarning,
+                       "Calling `mannwhitneyu` without .*`alternative`")
             u1, p1 = stats.mannwhitneyu(self.X, self.Y)
             u2, p2 = stats.mannwhitneyu(self.Y, self.X)
             u3, p3 = stats.mannwhitneyu(self.X, self.Y, alternative=None)
@@ -3490,8 +3489,9 @@ def test_mannwhitneyu_no_correct_two_sided(self):
 
     def test_mannwhitneyu_no_correct_default(self):
         # The default value for alternative is None
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore", DeprecationWarning)
+        with suppress_warnings() as sup:
+            sup.filter(DeprecationWarning,
+                       "Calling `mannwhitneyu` without .*`alternative`")
             u1, p1 = stats.mannwhitneyu(self.X, self.Y, False)
             u2, p2 = stats.mannwhitneyu(self.Y, self.X, False)
             u3, p3 = stats.mannwhitneyu(self.X, self.Y, False,
@@ -3547,7 +3547,7 @@ def test_mannwhitneyu_ones(self):
     def test_mannwhitneyu_result_attributes(self):
         # test for namedtuple attribute results
         attributes = ('statistic', 'pvalue')
-        res = stats.mannwhitneyu(self.X, self.Y)
+        res = stats.mannwhitneyu(self.X, self.Y, alternative="less")
         check_named_results(res, attributes)
 
 


Code review comments:
diff_hunk: @@ -20,10 +20,10 @@ cdef public int wrap_PyUFunc_getfperr() nogil:
 cdef extern from "numpy/npy_math.h":
     double NPY_NAN
 
-cimport sf_error
-cimport _complexstuff
+from . cimport sf_error
+from . cimport _complexstuff
 cimport scipy.special._ufuncs_cxx
-from . import _ufuncs
+from scipy.special import _ufuncs
path: scipy/special/_cython_special.pxi
text: @author:
Well, this one was shitty. for some reason it did *not* work to keep that a . here, maybe it is the order, and it would work if I changed it. Probably a cython bug?