Repository: mne-tools/mne-bids

Issue:
issue with CI and inspect module
              @drammock @hoechenberger I think this is the failure that threw me off recently: https://github.com/mne-tools/mne-bids/actions/runs/9106401009/job/25033546552#step:20:1185


>  FAILED mne_bids/tests/test_inspect.py::test_inspect_single_file[True] - matplotlib._api.deprecation.MatplotlibDeprecationWarning: Auto-close()ing of figures upon backend switching is deprecated since 3.8 and will be removed in 3.10.  To suppress this warning, explicitly call plt.close('all') first.
FAILED mne_bids/tests/test_inspect.py::test_inspect_single_file[False] - UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown

_Originally posted by @sappelhoff in https://github.com/mne-tools/mne-bids/issues/1245#issuecomment-2114663602_
            
issue with CI and inspect module
              @drammock @hoechenberger I think this is the failure that threw me off recently: https://github.com/mne-tools/mne-bids/actions/runs/9106401009/job/25033546552#step:20:1185


>  FAILED mne_bids/tests/test_inspect.py::test_inspect_single_file[True] - matplotlib._api.deprecation.MatplotlibDeprecationWarning: Auto-close()ing of figures upon backend switching is deprecated since 3.8 and will be removed in 3.10.  To suppress this warning, explicitly call plt.close('all') first.
FAILED mne_bids/tests/test_inspect.py::test_inspect_single_file[False] - UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown

_Originally posted by @sappelhoff in https://github.com/mne-tools/mne-bids/issues/1245#issuecomment-2114663602_
            


Discussion:
I can replicate this locally on macos 14.4.1 (M2 chip).
I can replicate this locally on macos 14.4.1 (M2 chip).

Resolving patch:
diff --git a/doc/sphinxext/gen_cli.py b/doc/sphinxext/gen_cli.py
--- a/doc/sphinxext/gen_cli.py
+++ b/doc/sphinxext/gen_cli.py
@@ -8,13 +8,14 @@
 #          Stefan Appelhoff <stefan.appelhoff@mailbox.org>
 #
 # License: BSD-3-Clause
-import os
 import glob
-from os import path as op
+import os
+import shutil
 import sys
+from os import path as op
 
 import sphinx.util
-from mne.utils import run_subprocess, _replace_md5
+from mne.utils import hashfunc, run_subprocess
 
 
 def setup(app):
@@ -116,6 +117,17 @@ def generate_cli_rst(app=None):
     print("[Done]")
 
 
+def _replace_md5(fname):
+    """Replace a file based on MD5sum."""
+    # adapted from sphinx-gallery
+    assert fname.endswith(".new")
+    fname_old = fname[:-4]
+    if os.path.isfile(fname_old) and hashfunc(fname) == hashfunc(fname_old):
+        os.remove(fname)
+    else:
+        shutil.move(fname, fname_old)
+
+
 # This is useful for testing/iterating to see what the result looks like
 if __name__ == "__main__":
     generate_cli_rst()
diff --git a/mne_bids/inspect.py b/mne_bids/inspect.py
--- a/mne_bids/inspect.py
+++ b/mne_bids/inspect.py
@@ -208,7 +208,7 @@ def _keypress_callback(event):
             onset=[], duration=[], description=[], orig_time=raw.info["meas_date"]
         )
 
-    if matplotlib.get_backend() != "agg":
+    if matplotlib.get_backend().lower() != "agg":
         plt.show(block=True)
 
     _global_vars["raw_fig"] = fig
@@ -430,7 +430,7 @@ def _keypress_callback(event):
     fig.canvas.mpl_connect("close_event", _dont_save_callback)
     fig.canvas.mpl_connect("key_press_event", _keypress_callback)
 
-    if matplotlib.get_backend() != "agg":
+    if matplotlib.get_backend().lower() != "agg":
         fig.show()
 
     _global_vars["dialog_fig"] = fig


Test patch:
diff --git a/mne_bids/tests/test_inspect.py b/mne_bids/tests/test_inspect.py
--- a/mne_bids/tests/test_inspect.py
+++ b/mne_bids/tests/test_inspect.py
@@ -71,7 +71,7 @@ def test_inspect_single_file(tmp_path, save_changes):
     import matplotlib.pyplot as plt
     from mne.utils._testing import _click_ch_name
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)
@@ -115,7 +115,7 @@ def test_inspect_multiple_files(tmp_path):
     matplotlib = pytest.importorskip("matplotlib")
     import matplotlib.pyplot as plt
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)
@@ -143,7 +143,7 @@ def test_inspect_set_and_unset_bads(tmp_path):
     import matplotlib.pyplot as plt
     from mne.utils._testing import _click_ch_name
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)
@@ -217,7 +217,7 @@ def test_inspect_annotations(tmp_path):
     matplotlib = pytest.importorskip("matplotlib")
     import matplotlib.pyplot as plt
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)
@@ -273,7 +273,7 @@ def test_inspect_annotations_remove_all(tmp_path):
     matplotlib = pytest.importorskip("matplotlib")
     import matplotlib.pyplot as plt
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)
@@ -332,7 +332,7 @@ def test_inspect_dont_show_annotations(tmp_path):
     matplotlib = pytest.importorskip("matplotlib")
     import matplotlib.pyplot as plt
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)
@@ -350,7 +350,7 @@ def test_inspect_bads_and_annotations(tmp_path):
     import matplotlib.pyplot as plt
     from mne.utils._testing import _click_ch_name
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)
@@ -391,7 +391,7 @@ def test_inspect_auto_flats(tmp_path, save_changes):
     matplotlib = pytest.importorskip("matplotlib")
     import matplotlib.pyplot as plt
 
-    matplotlib.use("Agg")
+    matplotlib.use("agg")
     plt.close("all")
 
     bids_root = setup_bids_test_dir(tmp_path)