Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of README files with extensions #1318

Merged
merged 11 commits into from
Oct 11, 2024
1 change: 1 addition & 0 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^
Expand Down
59 changes: 57 additions & 2 deletions mne_bids/tests/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import json
import os.path as op
import shutil
from pathlib import Path

import mne
Expand Down Expand Up @@ -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"))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
13 changes: 12 additions & 1 deletion mne_bids/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down