Repository: obspy/obspy (Python)

Issue:
Handle "slepian" window that was removed in scipy
This is a follow up reminder for #3329. "Slepian" window was removed in scipy, so it is not usable in obspy as well. So we should either..
 - remove it
 - replace it if possible with its [replacement function in scipy](https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.windows.dpss.html)


Discussion:

Patch:
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index e94242514a..ba6c51c96e 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -14,6 +14,9 @@ Changes:
    * improve error messages when traces fail to get merged due to differing
      data type, sampling rate etc (see #3418)
    * add helper methods to change/unify byteorder on trace/stream (see #3418)
+   * window 'slepian' was removed in Trace/Stream.taper() as it was removed
+     from scipy with version 1.6, add new window 'dpss' that scipy promotes as
+     replacement but might need other parameters passed in (see #3331)
  - obspy.clients.filesystem:
    * update syntax for SQLAlchemy 2.0 compatibility (see #3269)
  - obspy.clients.fdsn
diff --git a/obspy/core/trace.py b/obspy/core/trace.py
index 93f1426ef0..d58f4bfd3b 100644
--- a/obspy/core/trace.py
+++ b/obspy/core/trace.py
@@ -2145,10 +2145,11 @@ def taper(self, max_percentage, type='hann', max_length=None,
             (uses: :func:`scipy.signal.windows.nuttall`)
         ``'parzen'``
             Parzen window. (uses: :func:`scipy.signal.windows.parzen`)
-        ``'slepian'``
-            Slepian window. (uses: :func:`scipy.signal.windows.slepian`)
         ``'triang'``
             Triangular window. (uses: :func:`scipy.signal.windows.triang`)
+        ``'dpss'``
+            Discrete Prolate Spheroidal Sequences window. (uses:
+            :func:`scipy.signal.windows.dpss`)
         """
         type = type.lower()
         side = side.lower()
diff --git a/setup.py b/setup.py
index ddb2c0b2e8..beddaf933b 100644
--- a/setup.py
+++ b/setup.py
@@ -552,11 +552,8 @@
         'kaiser = scipy.signal.windows:kaiser',
         'nuttall = scipy.signal.windows:nuttall',
         'parzen = scipy.signal.windows:parzen',
-        # TODO slepian has been removed from scipy with version 1.6.0
-        # see https://docs.scipy.org/doc/scipy/release/1.1.0-notes.html
-        # see https://docs.scipy.org/doc/scipy/release/1.6.0-notes.html
-        'slepian = scipy.signal.windows:slepian',
         'triang = scipy.signal.windows:triang',
+        'dpss = scipy.signal.windows:dpss',
         ],
     'obspy.plugin.trigger': [
         'recstalta = obspy.signal.trigger:recursive_sta_lta',


Test patch:
diff --git a/obspy/core/tests/test_trace.py b/obspy/core/tests/test_trace.py
index 4cbd7ccf55..d60b6ca7c1 100644
--- a/obspy/core/tests/test_trace.py
+++ b/obspy/core/tests/test_trace.py
@@ -12,6 +12,7 @@
 from obspy import Stream, Trace, __version__, read, read_inventory
 from obspy import UTCDateTime as UTC
 from obspy.core import Stats
+from obspy.core.util.base import _get_entry_points
 from obspy.io.xseed import Parser
 import pytest
 
@@ -2732,3 +2733,46 @@ def test_long_processing_list(self):
                 tr.trim(0.01)
             assert len(tr.stats.processing) == n
             assert len(record) == 1
+
+    def test_taper_scipy_plugins(self):
+        """
+        Test that scipy window functions work in taper() and just test that
+        they do something
+        """
+        scipy_windows = {
+            'barthann': {},
+            'bartlett': {},
+            'blackman': {},
+            'blackmanharris': {},
+            'bohman': {},
+            'boxcar': {},
+            'chebwin': {'at': 50},
+            'dpss': {'NW': 1},
+            'flattop': {},
+            'gaussian': {'std': 1},
+            'general_gaussian': {'p': 1, 'sig': 1},
+            'hamming': {},
+            'hann': {},
+            'kaiser': {'beta': 1},
+            'nuttall': {},
+            'parzen': {},
+            'triang': {}}
+        eps = _get_entry_points('obspy.plugin.taper')
+        # cosine is not from scipy, leave it out here
+        eps.pop('cosine')
+
+        # make sure we test all entry points defined in setup.py
+        assert eps.keys() == scipy_windows.keys()
+
+        ones = np.ones(10, dtype=np.float64)
+        tr_bkp = Trace(np.ones(10, dtype=np.float64))
+        for window, kwargs in scipy_windows.items():
+            tr = tr_bkp.copy()
+            tr.taper(max_percentage=0.4, type=window, **kwargs)
+            # boxcar actually doesnt change the data at all
+            if window == 'boxcar':
+                np.testing.assert_array_equal(tr.data, ones)
+                continue
+            # just test that the data changed..
+            with pytest.raises(AssertionError):
+                np.testing.assert_array_almost_equal(tr.data, ones)