From ed75468b8209d1fe3d9002163a38c433c70c3ddd Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 11 Oct 2024 13:39:01 +0200 Subject: [PATCH] Fix handling of README files with extensions (#1318) * we have a failing test! * lint fixes * check for existing README with all allowed extensions and use that one. * updated whats new * fix scope * Update doc/whats_new.rst Co-authored-by: Daniel McCloy * remove extra print command Co-authored-by: Daniel McCloy * do not cast to str * throw exception when more than one readme is encountered. * added a test for multiple readmes --------- Co-authored-by: Daniel McCloy --- doc/whats_new.rst | 1 + mne_bids/tests/test_update.py | 59 +++++++++++++++++++++++++++++++++-- mne_bids/write.py | 13 +++++++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index ed1e235b6..0bc77bb7a 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -59,6 +59,7 @@ Detailed list of changes - Dealing with alphanumeric ``sub`` entity labels is now fixed for :func:`~mne_bids.write_raw_bids`, by `Aaron Earle-Richardson`_ (:gh:`1291`) - When processing subject_info data that MNE Python imports as numpy arrays with only one item, MNE-BIDS now unpacks these, resulting in a correct participants.tsv, by `Thomas Hartmann`_ (:gh:`1310`) - Fixed broken links in examples 7 and 8, by `William Turner`_ (:gh:`1316`) +- All valid extensions for ``README`` files are now accepted. This prevents an extra ``README`` file being created, when one with a ``.txt``, ``.md``, or ``.rst`` extension is already present. By `Thomas Hartmann`_ (:gh:`1318`) ⚕️ Code health ^^^^^^^^^^^^^^ diff --git a/mne_bids/tests/test_update.py b/mne_bids/tests/test_update.py index 0a1b6cf8a..868462e74 100644 --- a/mne_bids/tests/test_update.py +++ b/mne_bids/tests/test_update.py @@ -5,6 +5,7 @@ import json import os.path as op +import shutil from pathlib import Path import mne @@ -38,7 +39,7 @@ ) -@pytest.fixture(scope="session") +@pytest.fixture(scope="function") def _get_bids_test_dir(tmp_path_factory): """Return path to a written test BIDS dir.""" bids_root = str(tmp_path_factory.mktemp("mnebids_utils_test_bids_ds")) @@ -76,7 +77,7 @@ def _get_bids_test_dir(tmp_path_factory): return bids_root -@pytest.fixture(scope="session") +@pytest.fixture(scope="function") def _get_sidecar_json_update_file(_get_bids_test_dir): """Return path to a sidecar JSON updating file.""" bids_root = _get_bids_test_dir @@ -292,3 +293,57 @@ def test_update_anat_landmarks(tmp_path): assert np.allclose( mri_json["AnatomicalLandmarkCoordinates"][landmark], expected_coords ) + + +@testing.requires_testing_data +@pytest.mark.parametrize("extension", [None, ".txt", ".rst", ".md"]) +def test_readme_conflicts(extension, _get_bids_test_dir): + """Test that exisiting README files are respected with any extension.""" + bids_root = _get_bids_test_dir + assert Path(bids_root, "README").exists() + all_readmes = Path(bids_root).rglob("README*") + assert len(list(all_readmes)) == 1 + if extension is not None: + shutil.move(Path(bids_root, "README"), Path(bids_root, f"README{extension}")) + + bids_path = BIDSPath( + subject="02", + session=session_id, + run=1, + acquisition=acq, + task=task, + suffix="meg", + root=_get_bids_test_dir, + ) + + raw_fname = op.join(data_path, "MEG", "sample", "sample_audvis_trunc_raw.fif") + raw = mne.io.read_raw_fif(raw_fname) + + write_raw_bids(raw, bids_path, overwrite=False) + all_readmes = Path(bids_root).rglob("README*") + assert len(list(all_readmes)) == 1 + shutil.rmtree(bids_root) + + +@testing.requires_testing_data +def test_multiple_readmes_invalid(_get_bids_test_dir): + """Test that multiple README files are not allowed.""" + bids_root = _get_bids_test_dir + assert Path(bids_root, "README").exists() + shutil.copy(Path(bids_root, "README"), Path(bids_root, "README.md")) + bids_path = BIDSPath( + subject="02", + session=session_id, + run=1, + acquisition=acq, + task=task, + suffix="meg", + root=_get_bids_test_dir, + ) + + raw_fname = op.join(data_path, "MEG", "sample", "sample_audvis_trunc_raw.fif") + raw = mne.io.read_raw_fif(raw_fname) + + with pytest.raises(RuntimeError, match="Multiple README files found"): + write_raw_bids(raw, bids_path, overwrite=False) + shutil.rmtree(bids_root) diff --git a/mne_bids/write.py b/mne_bids/write.py index 500d300ff..ec4ace2e2 100644 --- a/mne_bids/write.py +++ b/mne_bids/write.py @@ -1955,7 +1955,18 @@ def write_raw_bids( ) # For the remaining files, we can use BIDSPath to alter. - readme_fname = op.join(bids_path.root, "README") + readme_suffixes = ("", ".md", ".rst", ".txt") + found_readmes = sorted( + filter(lambda x: x.suffix in readme_suffixes, bids_path.root.glob("README*")) + ) + if len(found_readmes) > 1: + raise RuntimeError( + "Multiple README files found in the BIDS root folder. " + "This violates the BIDS specifications. " + "Please ensure there is only one README file." + ) + readme_fname = str((found_readmes or [bids_path.root / "README"])[0]) + participants_tsv_fname = op.join(bids_path.root, "participants.tsv") participants_json_fname = participants_tsv_fname.replace(".tsv", ".json")