From 446da75665115d703311f29ff0e72aca3dddb747 Mon Sep 17 00:00:00 2001 From: meandmytram Date: Sat, 12 Sep 2026 13:56:36 -0400 Subject: [PATCH 1/6] Warn at import when NumPy's LAPACK is Accelerate, and document the OpenBLAS wheel On the macOS arm64 NumPy 2.x wheels, which link Apple's Accelerate framework, the decoders' rank-deficient, wide-spectrum matrices made numpy.linalg.qr die with SIGBUS and numpy.linalg.svd trip malloc's heap-corruption check inside dgesdd (five crash reports from the [[72,12,6]] investigation), and a chi_max=400 decode returned wrong verdicts while every unit test passed. The OpenBLAS build of the same NumPy version (the macosx_11_0_arm64 wheel) runs the same reproducers clean. The backend now warns once at import when Accelerate is found behind NumPy (MDOPT_ALLOW_ACCELERATE=1 silences it) and the README gives the two commands that install the OpenBLAS wheel. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud --- README.md | 20 +++++++++++++++++ mdopt/backend/array.py | 43 +++++++++++++++++++++++++++++++++++++ tests/backend/test_array.py | 29 +++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/README.md b/README.md index bb70d3ec..e469f691 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,26 @@ Otherwise, you can clone the repository and use [poetry](https://python-poetry.o poetry install ``` +### A note on NumPy's BLAS on Apple silicon + +The macOS arm64 wheels of NumPy 2.x link Apple's Accelerate framework. On +mdopt's matrices (rank-deficient, with singular values spanning many orders +of magnitude) Accelerate's LAPACK corrupted memory: `numpy.linalg.qr` died +with SIGBUS, `numpy.linalg.svd` tripped malloc's heap check, and a +bivariate-bicycle decode returned wrong verdicts while every test passed. +mdopt warns at import when it finds Accelerate behind NumPy. The OpenBLAS +build of the same NumPy version is the `macosx_11_0_arm64` wheel: + +```bash +pip download "numpy==$(python -c 'import numpy; print(numpy.__version__)')" \ + --platform macosx_11_0_arm64 --only-binary=:all: --no-deps -d /tmp/numpy-openblas +pip install --force-reinstall --no-deps /tmp/numpy-openblas/*.whl +``` + +Set `MDOPT_ALLOW_ACCELERATE=1` to silence the warning if you must keep +Accelerate. Use `OMP_NUM_THREADS=1` (or `OPENBLAS_NUM_THREADS=1`) for the +per-process BLAS of worker pools. + ## Minimal example ```python diff --git a/mdopt/backend/array.py b/mdopt/backend/array.py index 2a13512a..b4ba1b09 100644 --- a/mdopt/backend/array.py +++ b/mdopt/backend/array.py @@ -60,6 +60,49 @@ def _load_backend(): GPU = _xp.__name__ == "cupy" +def _lapack_vendor(numpy_module) -> str: + """The LAPACK library NumPy was built against, lower-cased ('' if unknown).""" + try: + deps = numpy_module.show_config(mode="dicts")["Build Dependencies"] + return str(deps["lapack"]["name"]).lower() + except Exception: # pylint: disable=broad-except + return "" + + +def _warn_if_accelerate(numpy_module) -> None: + """Warn once when NumPy's LAPACK is Apple's Accelerate framework. + + On the macOS arm64 wheels of NumPy 2.x (which link Accelerate) the + decoders' rank-deficient, wide-spectrum matrices made ``linalg.qr`` die + with SIGBUS and ``linalg.svd`` trip malloc's heap-corruption check + inside dgesdd, and a [[72,12,6]] decode at chi_max=400 returned wrong + verdicts while every unit test passed. The OpenBLAS build of the same + NumPy version has none of this; it is the ``macosx_11_0_arm64`` wheel:: + + pip download numpy== --platform macosx_11_0_arm64 \ + --only-binary=:all: --no-deps -d /tmp/numpy-openblas + pip install --force-reinstall --no-deps /tmp/numpy-openblas/*.whl + + Set MDOPT_ALLOW_ACCELERATE=1 to silence the warning. + """ + if os.getenv("MDOPT_ALLOW_ACCELERATE") == "1": + return + if "accelerate" in _lapack_vendor(numpy_module): + warnings.warn( + "NumPy is built against Apple's Accelerate LAPACK, which corrupted " + "memory and produced wrong decoding verdicts on mdopt's matrices " + "(see mdopt.backend.array._warn_if_accelerate). Install the " + "OpenBLAS build of NumPy (the macosx_11_0_arm64 wheel) or set " + "MDOPT_ALLOW_ACCELERATE=1 to silence this warning.", + RuntimeWarning, + stacklevel=2, + ) + + +if not GPU: + _warn_if_accelerate(_xp) + + # ---------------------------------------------------------------------- # Introspection helpers # ---------------------------------------------------------------------- diff --git a/tests/backend/test_array.py b/tests/backend/test_array.py index 472ba3d8..8473f008 100644 --- a/tests/backend/test_array.py +++ b/tests/backend/test_array.py @@ -88,3 +88,32 @@ def test_stream_is_a_context_manager_on_numpy(monkeypatch): with module.stream(): pass module.synchronize() + + +def test_accelerate_lapack_warns_unless_allowed(monkeypatch): + """A NumPy built against Accelerate triggers a RuntimeWarning at import + time; MDOPT_ALLOW_ACCELERATE=1 silences it; other vendors are silent.""" + import warnings + from types import SimpleNamespace + + from mdopt.backend import array as backend + + def fake_numpy(vendor): + return SimpleNamespace( + show_config=lambda mode="dicts": { + "Build Dependencies": { + "lapack": {"name": vendor}, + "blas": {"name": vendor}, + } + } + ) + + monkeypatch.delenv("MDOPT_ALLOW_ACCELERATE", raising=False) + with pytest.warns(RuntimeWarning, match="Accelerate"): + backend._warn_if_accelerate(fake_numpy("accelerate")) + with warnings.catch_warnings(): + warnings.simplefilter("error") + backend._warn_if_accelerate(fake_numpy("scipy-openblas")) + monkeypatch.setenv("MDOPT_ALLOW_ACCELERATE", "1") + backend._warn_if_accelerate(fake_numpy("accelerate")) + assert backend._lapack_vendor(SimpleNamespace()) == "" From 0eb84e281d66710729e6aab712366c80e91b740d Mon Sep 17 00:00:00 2001 From: meandmytram Date: Sat, 12 Sep 2026 14:20:08 -0400 Subject: [PATCH 2/6] Warn for an Accelerate-linked SciPy as well, and document both OpenBLAS wheels The SVD helpers call SciPy's LAPACK too, and the SciPy macOS arm64 wheels link Accelerate like NumPy's; with only NumPy switched to OpenBLAS the reduced SVD path still returned a wrong factorisation (reconstruction error 0.15) or crashed, and with both switched it passes repeatedly. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud --- README.md | 12 ++++++++---- mdopt/backend/array.py | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e469f691..6942cc5d 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,17 @@ mdopt's matrices (rank-deficient, with singular values spanning many orders of magnitude) Accelerate's LAPACK corrupted memory: `numpy.linalg.qr` died with SIGBUS, `numpy.linalg.svd` tripped malloc's heap check, and a bivariate-bicycle decode returned wrong verdicts while every test passed. -mdopt warns at import when it finds Accelerate behind NumPy. The OpenBLAS -build of the same NumPy version is the `macosx_11_0_arm64` wheel: +The SciPy macOS wheels link Accelerate as well, and mdopt's SVD helpers +call SciPy's LAPACK too. mdopt warns at import when it finds Accelerate +behind either library. The OpenBLAS builds of the same versions are the +`macosx_11_0_arm64` NumPy wheel and the `macosx_12_0_arm64` SciPy wheel: ```bash pip download "numpy==$(python -c 'import numpy; print(numpy.__version__)')" \ - --platform macosx_11_0_arm64 --only-binary=:all: --no-deps -d /tmp/numpy-openblas -pip install --force-reinstall --no-deps /tmp/numpy-openblas/*.whl + --platform macosx_11_0_arm64 --only-binary=:all: --no-deps -d /tmp/openblas-wheels +pip download "scipy==$(python -c 'import scipy; print(scipy.__version__)')" \ + --platform macosx_12_0_arm64 --only-binary=:all: --no-deps -d /tmp/openblas-wheels +pip install --force-reinstall --no-deps /tmp/openblas-wheels/*.whl ``` Set `MDOPT_ALLOW_ACCELERATE=1` to silence the warning if you must keep diff --git a/mdopt/backend/array.py b/mdopt/backend/array.py index b4ba1b09..173eaa5e 100644 --- a/mdopt/backend/array.py +++ b/mdopt/backend/array.py @@ -99,8 +99,28 @@ def _warn_if_accelerate(numpy_module) -> None: ) +def _warn_if_scipy_accelerate() -> None: + """The same warning for SciPy, whose LAPACK the SVD helpers also call.""" + if os.getenv("MDOPT_ALLOW_ACCELERATE") == "1": + return + try: + scipy = importlib.import_module("scipy") + except ImportError: + return + if "accelerate" in _lapack_vendor(scipy): + warnings.warn( + "SciPy is built against Apple's Accelerate LAPACK (see " + "mdopt.backend.array._warn_if_accelerate); install the OpenBLAS " + "build (the macosx_12_0_arm64 wheel) or set " + "MDOPT_ALLOW_ACCELERATE=1 to silence this warning.", + RuntimeWarning, + stacklevel=2, + ) + + if not GPU: _warn_if_accelerate(_xp) + _warn_if_scipy_accelerate() # ---------------------------------------------------------------------- From 365c91db17a3b812b802ff723c5fd4de21d2fc50 Mon Sep 17 00:00:00 2001 From: meandmytram Date: Sun, 13 Sep 2026 13:33:04 -0400 Subject: [PATCH 3/6] Detect SciPy 1.9's LAPACK too, and say which macOS wheels link Accelerate SciPy 1.10 and later report their LAPACK through show_config(mode="dicts"), but SciPy 1.9, which the dependency floor allows, has show() without a mode argument, so the SciPy check silently reported an unknown vendor there. The helper now falls back to __config__.get_info("lapack_opt") in that case, and two SciPy-shaped test doubles cover both APIs. The README said the macOS arm64 wheels link Accelerate; only the macosx_14_0_arm64 wheels do (checked NumPy 2.4.6, SciPy 1.15.3 and 1.18.1), which pip picks on macOS 14 and later, while the macosx_11_0_arm64 NumPy and macosx_12_0_arm64 SciPy wheels bundle OpenBLAS. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud --- README.md | 19 +++++++------- mdopt/backend/array.py | 23 +++++++++++++--- tests/backend/test_array.py | 52 +++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6942cc5d..cf9105f9 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,16 @@ poetry install ### A note on NumPy's BLAS on Apple silicon -The macOS arm64 wheels of NumPy 2.x link Apple's Accelerate framework. On -mdopt's matrices (rank-deficient, with singular values spanning many orders -of magnitude) Accelerate's LAPACK corrupted memory: `numpy.linalg.qr` died -with SIGBUS, `numpy.linalg.svd` tripped malloc's heap check, and a -bivariate-bicycle decode returned wrong verdicts while every test passed. -The SciPy macOS wheels link Accelerate as well, and mdopt's SVD helpers -call SciPy's LAPACK too. mdopt warns at import when it finds Accelerate -behind either library. The OpenBLAS builds of the same versions are the -`macosx_11_0_arm64` NumPy wheel and the `macosx_12_0_arm64` SciPy wheel: +On Apple silicon running macOS 14 or later, pip installs the NumPy and +SciPy wheels tagged `macosx_14_0_arm64`, which link Apple's Accelerate +framework. On mdopt's matrices (rank-deficient, with singular values +spanning many orders of magnitude) Accelerate's LAPACK corrupted memory: +`numpy.linalg.qr` died with SIGBUS, `numpy.linalg.svd` tripped malloc's +heap check, and a bivariate-bicycle decode returned wrong verdicts while +every test passed. mdopt's SVD helpers call both libraries, and mdopt warns +at import when it finds Accelerate behind either one. The same versions are +also published as OpenBLAS builds, the `macosx_11_0_arm64` NumPy wheel and +the `macosx_12_0_arm64` SciPy wheel, which install on the same machines: ```bash pip download "numpy==$(python -c 'import numpy; print(numpy.__version__)')" \ diff --git a/mdopt/backend/array.py b/mdopt/backend/array.py index 173eaa5e..ace4a686 100644 --- a/mdopt/backend/array.py +++ b/mdopt/backend/array.py @@ -60,13 +60,30 @@ def _load_backend(): GPU = _xp.__name__ == "cupy" -def _lapack_vendor(numpy_module) -> str: - """The LAPACK library NumPy was built against, lower-cased ('' if unknown).""" +def _lapack_vendor(module) -> str: + """The LAPACK library a NumPy or SciPy module was built against, lower-cased. + + NumPy and SciPy 1.10 and later report it through + ``show_config(mode="dicts")``. SciPy 1.9 (a numpy.distutils build) has no + ``mode`` argument and exposes its link information through + ``__config__.get_info`` instead; an Accelerate link there is reported as + ``"accelerate"``. Returns ``""`` when neither source is available. + """ try: - deps = numpy_module.show_config(mode="dicts")["Build Dependencies"] + deps = module.show_config(mode="dicts")["Build Dependencies"] return str(deps["lapack"]["name"]).lower() + except TypeError: + pass # show_config without a mode argument: fall through to get_info + except Exception: # pylint: disable=broad-except + return "" + try: + info = module.__config__.get_info("lapack_opt") except Exception: # pylint: disable=broad-except return "" + text = " ".join(str(value) for value in dict(info).values()).lower() + if "accelerate" in text or "veclib" in text: + return "accelerate" + return text def _warn_if_accelerate(numpy_module) -> None: diff --git a/tests/backend/test_array.py b/tests/backend/test_array.py index 8473f008..38b44721 100644 --- a/tests/backend/test_array.py +++ b/tests/backend/test_array.py @@ -117,3 +117,55 @@ def fake_numpy(vendor): monkeypatch.setenv("MDOPT_ALLOW_ACCELERATE", "1") backend._warn_if_accelerate(fake_numpy("accelerate")) assert backend._lapack_vendor(SimpleNamespace()) == "" + + +def test_scipy_shaped_config_is_detected(monkeypatch): + """SciPy 1.10+ reports its LAPACK through show_config(mode="dicts"), with + the vendor capitalised ("Accelerate"); the SciPy check must warn on it.""" + from types import SimpleNamespace + + from mdopt.backend import array as backend + + def show_config(mode="stdout"): + if mode == "stdout": + return None + return { + "Build Dependencies": { + "blas": {"name": "Accelerate"}, + "lapack": {"name": "Accelerate"}, + } + } + + monkeypatch.delenv("MDOPT_ALLOW_ACCELERATE", raising=False) + monkeypatch.setitem(sys.modules, "scipy", SimpleNamespace(show_config=show_config)) + with pytest.warns(RuntimeWarning, match="SciPy"): + backend._warn_if_scipy_accelerate() + + +def test_scipy_without_show_config_mode_falls_back_to_get_info(monkeypatch): + """SciPy 1.9 has show() without a mode argument; its link information + comes from __config__.get_info, which must still detect Accelerate and + stay silent for OpenBLAS.""" + from types import SimpleNamespace + + from mdopt.backend import array as backend + + def show(): + return None + + def scipy_with(info): + return SimpleNamespace( + show_config=show, __config__=SimpleNamespace(get_info=lambda name: info) + ) + + monkeypatch.delenv("MDOPT_ALLOW_ACCELERATE", raising=False) + accelerate = scipy_with({"extra_link_args": ["-Wl,-framework", "-Wl,Accelerate"]}) + openblas = scipy_with({"libraries": ["openblas", "openblas"], "language": "c"}) + assert backend._lapack_vendor(accelerate) == "accelerate" + monkeypatch.setitem(sys.modules, "scipy", accelerate) + with pytest.warns(RuntimeWarning, match="SciPy"): + backend._warn_if_scipy_accelerate() + monkeypatch.setitem(sys.modules, "scipy", openblas) + with warnings.catch_warnings(): + warnings.simplefilter("error") + backend._warn_if_scipy_accelerate() From 0ae40a696b051b883dc948392a351bffe596c638 Mon Sep 17 00:00:00 2001 From: meandmytram Date: Sun, 13 Sep 2026 17:18:28 -0400 Subject: [PATCH 4/6] Allow the Accelerate import warnings in the no-warnings backend test test_defaults_to_numpy asserted that importing the backend warns about nothing, which fails on exactly the builds the new warning targets: the macOS CI runners install the Accelerate-linked NumPy and SciPy wheels, and all three macOS test jobs failed on it. The test now allows RuntimeWarnings that mention Accelerate and still fails on any other warning. Checked with NumPy and SciPy made to report Accelerate: the backend tests and the full suite pass. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud --- tests/backend/test_array.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/backend/test_array.py b/tests/backend/test_array.py index 38b44721..10d43d8a 100644 --- a/tests/backend/test_array.py +++ b/tests/backend/test_array.py @@ -45,11 +45,23 @@ def get_device_count(): def test_defaults_to_numpy(monkeypatch): - """With no MDOPT_BACKEND set, NumPy is used and nothing is warned about.""" + """With no MDOPT_BACKEND set, NumPy is used and nothing unexpected is warned about. + + The import deliberately warns when NumPy or SciPy links Apple's Accelerate + framework, which the stock macOS 14+ wheels do (the macOS CI runners among + them); those warnings are allowed, any other warning is not. + """ module, caught = _reload_backend(monkeypatch, None, None) assert module.GPU is False assert module.backend_name() == "numpy" - assert not caught + unexpected = [ + w + for w in caught + if not ( + issubclass(w.category, RuntimeWarning) and "Accelerate" in str(w.message) + ) + ] + assert not unexpected, [str(w.message) for w in unexpected] def test_falls_back_when_cupy_missing(monkeypatch): From 6983106dfb354ecdeb6ebbced9f692c3f15f9f6b Mon Sep 17 00:00:00 2001 From: meandmytram Date: Sun, 13 Sep 2026 18:25:14 -0400 Subject: [PATCH 5/6] Warn about an Accelerate-linked NumPy or SciPy on every backend The import-time checks were skipped when CuPy was selected, yet the GPU path still runs NumPy's linalg and BLAS on the host (orthogonality-centre moves, host-side contractions) and SciPy's LAPACK in the SVD fallbacks and in qr, so a GPU user on the stock macOS wheels was exposed to the same corruption without a warning. Both checks now run regardless of the backend. The CuPy-selection test allows the Accelerate warnings, and a new test checks that they fire with CuPy selected. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud --- mdopt/backend/array.py | 8 +++++--- tests/backend/test_array.py | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/mdopt/backend/array.py b/mdopt/backend/array.py index ace4a686..553c1538 100644 --- a/mdopt/backend/array.py +++ b/mdopt/backend/array.py @@ -135,9 +135,11 @@ def _warn_if_scipy_accelerate() -> None: ) -if not GPU: - _warn_if_accelerate(_xp) - _warn_if_scipy_accelerate() +# Both checks run on every backend: with CuPy selected the orthogonality-centre +# moves and host-side contractions still call NumPy's linalg and BLAS, and the +# SVD fallbacks and qr call SciPy's LAPACK. +_warn_if_accelerate(importlib.import_module("numpy")) +_warn_if_scipy_accelerate() # ---------------------------------------------------------------------- diff --git a/tests/backend/test_array.py b/tests/backend/test_array.py index 10d43d8a..ddd8f72f 100644 --- a/tests/backend/test_array.py +++ b/tests/backend/test_array.py @@ -91,7 +91,14 @@ def test_uses_cupy_when_device_present(monkeypatch): module, caught = _reload_backend(monkeypatch, "cupy", _fake_cupy(num_devices=1)) assert module.GPU is True assert module.backend_name() == "cupy" - assert not caught + unexpected = [ + w + for w in caught + if not ( + issubclass(w.category, RuntimeWarning) and "Accelerate" in str(w.message) + ) + ] + assert not unexpected, [str(w.message) for w in unexpected] def test_stream_is_a_context_manager_on_numpy(monkeypatch): @@ -181,3 +188,30 @@ def scipy_with(info): with warnings.catch_warnings(): warnings.simplefilter("error") backend._warn_if_scipy_accelerate() + + +def test_accelerate_warnings_fire_on_the_gpu_backend(monkeypatch): + """With CuPy selected, NumPy and SciPy LAPACK still run on the host (centre + moves, host-side contractions, the SVD fallbacks, qr), so an + Accelerate-linked build must still be warned about.""" + import numpy + import scipy + + def faked(real): + def show_config(mode="stdout"): + if mode == "stdout": + return None + config = real(mode="dicts") + config["Build Dependencies"]["lapack"]["name"] = "accelerate" + return config + + return show_config + + monkeypatch.delenv("MDOPT_ALLOW_ACCELERATE", raising=False) + monkeypatch.setattr(numpy, "show_config", faked(numpy.show_config)) + monkeypatch.setattr(scipy, "show_config", faked(scipy.show_config)) + module, caught = _reload_backend(monkeypatch, "cupy", _fake_cupy(num_devices=1)) + assert module.GPU is True + messages = [str(w.message) for w in caught] + assert any("NumPy is built against" in m for m in messages), messages + assert any("SciPy is built against" in m for m in messages), messages From 9065231463b7ce0d18adc0bed6c12450945edfe0 Mon Sep 17 00:00:00 2001 From: meandmytram Date: Mon, 14 Sep 2026 10:57:32 -0400 Subject: [PATCH 6/6] Give the GPU-backend warning test a synthetic config The test faked show_config by delegating to the installed function with mode="dicts", which SciPy 1.9 (still allowed by the dependency floor and handled by _lapack_vendor) does not accept; there the helper fell back to the real OpenBLAS config and the expected SciPy warning never fired. The fake now returns a synthetic modern config and no longer touches the installed API. Checked with real OpenBLAS, with NumPy and SciPy reporting Accelerate, and with SciPy's show_config replaced by the 1.9 signature. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud --- tests/backend/test_array.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/backend/test_array.py b/tests/backend/test_array.py index ddd8f72f..9d553c34 100644 --- a/tests/backend/test_array.py +++ b/tests/backend/test_array.py @@ -197,19 +197,21 @@ def test_accelerate_warnings_fire_on_the_gpu_backend(monkeypatch): import numpy import scipy - def faked(real): - def show_config(mode="stdout"): - if mode == "stdout": - return None - config = real(mode="dicts") - config["Build Dependencies"]["lapack"]["name"] = "accelerate" - return config - - return show_config + def show_config(mode="stdout"): + # A synthetic modern config, independent of the installed versions' + # show_config API (SciPy 1.9 has no mode argument). + if mode == "stdout": + return None + return { + "Build Dependencies": { + "blas": {"name": "accelerate"}, + "lapack": {"name": "accelerate"}, + } + } monkeypatch.delenv("MDOPT_ALLOW_ACCELERATE", raising=False) - monkeypatch.setattr(numpy, "show_config", faked(numpy.show_config)) - monkeypatch.setattr(scipy, "show_config", faked(scipy.show_config)) + monkeypatch.setattr(numpy, "show_config", show_config) + monkeypatch.setattr(scipy, "show_config", show_config) module, caught = _reload_backend(monkeypatch, "cupy", _fake_cupy(num_devices=1)) assert module.GPU is True messages = [str(w.message) for w in caught]