From 64501c3ff5bdb9eeaca62ada4045759ba34a2793 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Tue, 6 Aug 2024 16:49:50 -0400 Subject: [PATCH 1/2] BUG: Fix bug with doc rebuilds being forced --- doc/sphinxext/contrib_avatars.py | 5 ++++- doc/sphinxext/gen_commands.py | 15 +-------------- mne/utils/__init__.pyi | 2 ++ mne/utils/numerics.py | 13 +++++++++++++ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/doc/sphinxext/contrib_avatars.py b/doc/sphinxext/contrib_avatars.py index 04583ac4c77..299e074dd4d 100644 --- a/doc/sphinxext/contrib_avatars.py +++ b/doc/sphinxext/contrib_avatars.py @@ -3,12 +3,14 @@ import os from pathlib import Path +from mne.utils import _replace_md5 + def generate_contrib_avatars(app, config): """Render a template webpage with avatars generated by JS and a GitHub API call.""" root = Path(app.srcdir) infile = root / "sphinxext" / "_avatar_template.html" - outfile = root / "_templates" / "avatars.html" + outfile = root / "_templates" / "avatars.html.new" if os.getenv("MNE_ADD_CONTRIBUTOR_IMAGE", "false").lower() != "true": body = """\

Contributor avators will appear here in full doc builds. Set \ @@ -36,6 +38,7 @@ def generate_contrib_avatars(app, config): driver.quit() with open(outfile, "w") as fid: fid.write(body) + _replace_md5(str(outfile)) def setup(app): diff --git a/doc/sphinxext/gen_commands.py b/doc/sphinxext/gen_commands.py index 730d3e47caf..c369bba6db0 100644 --- a/doc/sphinxext/gen_commands.py +++ b/doc/sphinxext/gen_commands.py @@ -1,12 +1,10 @@ # License: BSD-3-Clause # Copyright the MNE-Python contributors. import glob -import os -import shutil from importlib import import_module from pathlib import Path -from mne.utils import ArgvSetter, hashfunc +from mne.utils import ArgvSetter, _replace_md5 def setup(app): @@ -108,17 +106,6 @@ def generate_commands_rst(app=None): _replace_md5(str(out_fname)) -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_commands_rst() diff --git a/mne/utils/__init__.pyi b/mne/utils/__init__.pyi index 2eaa9aba6ad..46d272e972d 100644 --- a/mne/utils/__init__.pyi +++ b/mne/utils/__init__.pyi @@ -98,6 +98,7 @@ __all__ = [ "_reg_pinv", "_reject_data_segments", "_repeated_svd", + "_replace_md5", "_require_version", "_resource_path", "_safe_input", @@ -361,6 +362,7 @@ from .numerics import ( _mask_to_onsets_offsets, _reg_pinv, _reject_data_segments, + _replace_md5, _ReuseCycle, _scaled_array, _stamp_to_dt, diff --git a/mne/utils/numerics.py b/mne/utils/numerics.py index 053f04362ec..433c1eb6445 100644 --- a/mne/utils/numerics.py +++ b/mne/utils/numerics.py @@ -8,6 +8,8 @@ import inspect import numbers import operator +import os +import shutil import sys from contextlib import contextmanager from datetime import date, datetime, timedelta, timezone @@ -1104,3 +1106,14 @@ def _array_repr(x): """Produce compact info about float ndarray x.""" assert isinstance(x, np.ndarray), type(x) return f"shape : {x.shape}, range : [{np.nanmin(x):+0.2g}, {np.nanmax(x):+0.2g}]" + + +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) From 484d9f7443e221ec68df5f7a852bad31c93fb2c2 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Tue, 6 Aug 2024 17:32:43 -0400 Subject: [PATCH 2/2] FIX: Basic test --- mne/utils/tests/test_numerics.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mne/utils/tests/test_numerics.py b/mne/utils/tests/test_numerics.py index 599b8d27bfb..3c1eadf74cd 100644 --- a/mne/utils/tests/test_numerics.py +++ b/mne/utils/tests/test_numerics.py @@ -26,6 +26,7 @@ _get_inst_data, _julian_to_date, _reg_pinv, + _replace_md5, _ReuseCycle, _time_mask, _undo_scaling_array, @@ -602,3 +603,20 @@ def my_fun_2(*args): with pytest.raises(RuntimeError, match="Unsupported sparse type"): my_fun_2(1, _eye_array(1, format="coo")) assert n_calls == [2, 2] # never did any computation + + +def test_replace_md5(tmp_path): + """Test _replace_md5.""" + old = tmp_path / "test" + new = old.with_suffix(".new") + old.write_text("abcd") + new.write_text("abcde") + assert old.is_file() + assert new.is_file() + _replace_md5(str(new)) + assert not new.is_file() + assert old.read_text() == "abcde" + new.write_text(old.read_text()) + _replace_md5(str(new)) + assert old.read_text() == "abcde" + assert not new.is_file()