PyWavelets / pywt

PyWavelets - Wavelet Transforms in Python
http://pywavelets.readthedocs.org
MIT License
1.96k stars 460 forks source link

`test_concurrent_cwt` failure on macOS arm64 with free-threaded CPython #758

Open rgommers opened 2 days ago

rgommers commented 2 days ago

We have a set of concurrent tests that use concurrent.futures.ThreadPoolExecutor. It has never failed before AFAIK; the tests also passed a number of times already with the new Linux free-threaded CI. It just now failed for the first time in the macOS arm64 free-threaded wheel build job (from the CI log):

_____________________________ test_concurrent_cwt ______________________________

      @uses_futures
      def test_concurrent_cwt():
          atol = rtol = 1e-14
          time, sst = pywt.data.nino()
          dt = time[1]-time[0]
          transform = partial(pywt.cwt, scales=np.arange(1, 4), wavelet='cmor1.5-1',
                              sampling_period=dt)
          for _ in range(10):
              arrs = [sst.copy() for _ in range(50)]
              with futures.ThreadPoolExecutor(max_workers=max_workers) as ex:
  >               results = list(ex.map(transform, arrs))

...

   ../venv-test-arm64/lib/python3.13/site-packages/pywt/tests/test_concurrent.py:101: 
  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
  /Library/Frameworks/PythonT.framework/Versions/3.13/lib/python3.13/concurrent/futures/_base.py:619: in result_iterator
      yield _result_or_cancel(fs.pop())
  /Library/Frameworks/PythonT.framework/Versions/3.13/lib/python3.13/concurrent/futures/_base.py:317: in _result_or_cancel
      return fut.result(timeout)
  /Library/Frameworks/PythonT.framework/Versions/3.13/lib/python3.13/concurrent/futures/_base.py:456: in result
      return self.__get_result()
  /Library/Frameworks/PythonT.framework/Versions/3.13/lib/python3.13/concurrent/futures/_base.py:401: in __get_result
      raise self._exception
  /Library/Frameworks/PythonT.framework/Versions/3.13/lib/python3.13/concurrent/futures/thread.py:58: in run
      result = self.fn(*self.args, **self.kwargs)
  ../venv-test-arm64/lib/python3.13/site-packages/pywt/_cwt.py:202: in cwt
      frequencies = scale2frequency(wavelet, scales, precision)
  ../venv-test-arm64/lib/python3.13/site-packages/pywt/_functions.py:183: in scale2frequency
      return central_frequency(wavelet, precision=precision) / scale
...
          index = np.argmax(abs(fft(psi)[1:])) + 2
  >       if index > len(psi) / 2:
  E       TypeError: A loop/promoter has already been registered with 'greater' for (<class 'numpy.dtypes.Float64DType'>, <class 'numpy.dtypes.Float64DType'>, <class 'numpy.dtypes.BoolDType'>)

  ../venv-test-arm64/lib/python3.13/site-packages/pywt/_functions.py:156: TypeError
  =========================== short test summary info ============================
  FAILED tests/test_concurrent.py::test_concurrent_cwt - TypeError: A loop/promoter has already been registered with 'greater' for (<class 'numpy.dtypes.Float64DType'>, <class 'numpy.dtypes.Float64DType'>, <class 'numpy.dtypes.BoolDType'>)
  ================ 1 failed, 812 passed, 225 deselected in 4.72s =================

That looks like a missing lock around a cache in NumPy, which is probably already fixed by one of @ngoldbaum's PRs.

rgommers commented 2 days ago

Some of the NumPy wheels at https://anaconda.org/scientific-python-nightly-wheels/numpy/files are 11 days old, which is due to gh-26810. So if the fix landed already in numpy's main branch, it may still not have propagated.

ngoldbaum commented 2 days ago

I'm able to reproduce random failures and seg faults on this test using the wheel. I think rebuilding it will make this test more stable.

That said, I do see a failure running a different test in the same file on the latest numpy main:

``` ================================= test session starts ================================== platform darwin -- Python 3.13.0b2, pytest-8.2.2, pluggy-1.5.0 -- /Users/goldbaum/.pyenv/versions/3.13.0b2-nogil/bin/python cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase(PosixPath('/Users/goldbaum/Documents/pywt/.hypothesis/examples')) rootdir: /Users/goldbaum/Documents/pywt configfile: pytest.ini plugins: hypothesis-6.103.1 collected 4 items pywt/tests/test_concurrent.py::test_concurrent_swt PASSED [ 25%] pywt/tests/test_concurrent.py::test_concurrent_wavedec PASSED [ 50%] pywt/tests/test_concurrent.py::test_concurrent_dwt FAILED [ 75%] pywt/tests/test_concurrent.py::test_concurrent_cwt PASSED [100%] ======================================= FAILURES ======================================= _________________________________ test_concurrent_dwt __________________________________ @uses_futures def test_concurrent_dwt(): # dwt on 1D data calls the Cython dwt_single # other cases call dwt_axis for dwt_func, x in zip([pywt.dwt, pywt.dwt2, pywt.dwtn], [np.ones(8), np.eye(16), np.eye(16)]): transform = partial(dwt_func, wavelet='haar') for _ in range(10): arrs = [x.copy() for _ in range(100)] with futures.ThreadPoolExecutor(max_workers=max_workers) as ex: > results = list(ex.map(transform, arrs)) _ = 1 arrs = [array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.])] dwt_func = ex = results = [(array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.])), (array([1.41421356, 1.41421356, 1.41421356, 1.41421356]), array([0., 0., 0., 0.]))] transform = functools.partial(, wavelet='haar') x = array([1., 1., 1., 1., 1., 1., 1., 1.]) pywt/tests/test_concurrent.py:84: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ../../.pyenv/versions/3.13.0b2-nogil/lib/python3.13/concurrent/futures/_base.py:608: in map fs = [self.submit(fn, *args) for args in zip(*iterables)] chunksize = 1 fn = functools.partial(, wavelet='haar') iterables = ([array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.]), array([1., 1., 1., 1., 1., 1., 1., 1.])],) self = timeout = None _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = fn = functools.partial(, wavelet='haar') args = (array([1., 1., 1., 1., 1., 1., 1., 1.]),), kwargs = {} def submit(self, fn, /, *args, **kwargs): > with self._shutdown_lock, _global_shutdown_lock: E TypeError: descriptor '__enter__' for '_thread.RLock' objects doesn't apply to a '_thread.lock' object args = (array([1., 1., 1., 1., 1., 1., 1., 1.]),) fn = functools.partial(, wavelet='haar') kwargs = {} self = ../../.pyenv/versions/3.13.0b2-nogil/lib/python3.13/concurrent/futures/thread.py:165: TypeError =============================== short test summary info ================================ FAILED pywt/tests/test_concurrent.py::test_concurrent_dwt - TypeError: descriptor '__enter__' for '_thread.RLock' objects doesn't apply to a '_thread.lock' object ============================= 1 failed, 3 passed in 0.39s =================== ```

No idea why this fails randomly (a few percent of the time on my M3 Mac) in this way.

rgommers commented 2 days ago

Thanks for checking @ngoldbaum.

That second failure looks like a problem in either CPython or Cython:

self = <concurrent.futures.thread.ThreadPoolExecutor object at 0x266bfb95f10>
fn = functools.partial(<function dwt at 0x266bfcc05a0>, wavelet='haar')
args = (array([1., 1., 1., 1., 1., 1., 1., 1.]),), kwargs = {}

    def submit(self, fn, /, *args, **kwargs):
>       with self._shutdown_lock, _global_shutdown_lock:
E       TypeError: descriptor '__enter__' for '_thread.RLock' objects doesn't apply to a '_thread.lock' object

args       = (array([1., 1., 1., 1., 1., 1., 1., 1.]),)
fn         = functools.partial(<function dwt at 0x266bfcc05a0>, wavelet='haar')
kwargs     = {}
self       = <concurrent.futures.thread.ThreadPoolExecutor object at 0x266bfb95f10>

../../.pyenv/versions/3.13.0b2-nogil/lib/python3.13/concurrent/futures/thread.py:165: TypeError
=============================== short test summary info ================================
FAILED pywt/tests/test_concurrent.py::test_concurrent_dwt - TypeError: descriptor '__enter__' for '_thread.RLock' objects doesn't apply to a '_thread.lock' object
============================= 1 failed, 3 passed in 0.39s ===================

I can't find any existing bug report for this; _thread.RLock does have a ton of bug reports related to it not being pickle-able, but nothing is doing that in this test case.