Skip to content

Commit 734b427

Browse files
authored
Merge branch 'main' into main
2 parents be2b713 + a478527 commit 734b427

File tree

13 files changed

+237
-60
lines changed

13 files changed

+237
-60
lines changed

.github/release.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
changelog:
2+
exclude:
3+
authors:
4+
- dependabot[bot]
5+
- pre-commit-ci[bot]
6+
- github-actions[bot]

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: v0.12.12
3+
rev: v0.13.1
44
hooks:
55
- id: ruff
66
name: ruff mne_bids/
@@ -33,7 +33,7 @@ repos:
3333
- id: check-docstring-first
3434

3535
- repo: https://github.com/pappasam/toml-sort
36-
rev: v0.24.2
36+
rev: v0.24.3
3737
hooks:
3838
- id: toml-sort-fix
3939
files: pyproject.toml

CITATION.cff

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ authors:
214214
family-names: Ritz
215215
affiliation: 'Princeton Neuroscience Institute, Princeton University, Princeton, USA'
216216
orcid: 'https://orcid.org/0009-0003-1477-4912'
217+
- given-names: Alex
218+
family-names: Lopez Marquez
219+
affiliation: 'Institut Guttmann, Barcelona, Spain'
220+
orcid: 'https://orcid.org/0000-0002-3353-280X'
217221
- given-names: Nathan
218222
family-names: Azrak
219223
orcid: 'https://orcid.org/0000-0001-7695-4634'

doc/_static/versions.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
[
22
{
3-
"name": "0.17 (devel)",
3+
"name": "0.18 (devel)",
44
"version": "dev",
55
"url": "https://mne.tools/mne-bids/dev/"
66
},
77
{
8-
"name": "0.16 (stable)",
8+
"name": "0.17 (stable)",
99
"version": "stable",
10+
"url": "https://mne.tools/mne-bids/v0.17/"
11+
},
12+
{
13+
"name": "0.16",
14+
"version": "0.16",
1015
"url": "https://mne.tools/mne-bids/v0.16/"
1116
},
1217
{

doc/authors.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.. _Aaron Earle-Richardson: https://github.com/Aaronearlerichardson
22
.. _Adam Li: https://github.com/adam2392
3+
.. _Alex Lopez Marquez: https://github.com/alm180
34
.. _Alex Rockhill: https://github.com/alexrockhill
45
.. _Alexandre Gramfort: http://alexandre.gramfort.net
56
.. _Amaia Benitez: https://github.com/AmaiaBA
@@ -55,6 +56,7 @@
5556
.. _Teon Brooks: https://teonbrooks.com
5657
.. _Thomas Hartmann: https://github.com/thht
5758
.. _Tom Donoghue: https://github.com/TomDonoghue
59+
.. _waldie11: https://github.com/waldie11
5860
.. _William Turner: https://bootstrapbill.github.io/
5961
.. _Yorguin Mantilla: https://github.com/yjmantilla
6062
.. _Julius Welzel: https://github.com/JuliusWelzel

doc/whats_new.rst

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

55
.. currentmodule:: mne_bids
66

7+
.. include:: authors.rst
8+
79
What's new?
810
===========
911

10-
.. _changes_0_17:
12+
.. _changes_0_18:
1113

12-
Version 0.17 (unreleased)
14+
Version 0.18 (unreleased)
1315
-------------------------
1416

1517
👩🏽‍💻 Authors
@@ -24,59 +26,40 @@ The following authors contributed for the first time. Thank you so much! 🤩
2426
* `Harrison Ritz`_
2527
* `Julius Welzel`_
2628
* `Nathan Azrak`_
29+
* `Alex Lopez Marquez`_
2730

2831

2932
The following authors had contributed before. Thank you for sticking around! 🤘
3033

31-
* `Stefan Appelhoff`_
32-
* `Daniel McCloy`_
33-
* `Scott Huberty`_
34-
* `Pierre Guetschel`_
35-
* `Teon Brooks`_
34+
* TBD
35+
3636

3737
Detailed list of changes
3838
~~~~~~~~~~~~~~~~~~~~~~~~
3939

4040
🚀 Enhancements
4141
^^^^^^^^^^^^^^^
4242

43-
- :func:`mne_bids.write_raw_bids()` can now handle mne `Raw` objects with `eyegaze` and `pupil` channels, by `Christian O'Reilly`_ (:gh:`1344`)
44-
- :func:`mne_bids.get_entity_vals()` has a new parameter ``ignore_suffixes`` to easily ignore sidecar files, by `Daniel McCloy`_ (:gh:`1362`)
45-
- Empty-room matching now preferentially finds recordings in the subject directory tagged as `task-noise` before looking in the `sub-emptyroom` directories. This adds support for a part of the BIDS specification for ER recordings, by `Berk Gerçek`_ (:gh:`1364`)
46-
- Path matching is now implemenented in a more efficient manner within :meth:`mne_bids.BIDSPath.match()` and :func:`mne_bids.find_matching_paths()`, by `Arne Gottwald` (:gh:`1355`)
47-
- :func:`mne_bids.get_entity_vals()` has a new parameter ``include_match`` to prefilter item matching and ignore non-matched items from begin of directory scan, by `Arne Gottwald` (:gh:`1355`)
48-
- Data from ``events.tsv`` can now be read into an OrderedDict using :func:`mne_bids.events_file_to_annotation_kwargs()`, by `Matthias Dold` (:gh:`1389`)
49-
- Read the optionally present extra columns from ``events.tsv`` and pass them to :class:`mne.Annotations`, by `Pierre Guetschel` (:gh:`1401`)
50-
- ``_filter_fnames()`` now correctly checks the default extension, correcting suffix filtering, by `Nathan Azrak` (:gh:`1427`)
51-
43+
- :func:`mne_bids.write_raw_bids()` has a new parameter `electrodes_tsv_task` which allows adding the `task` entity to the `electrodes.tsv` filepath, by `Alex Lopez Marquez`_ (:gh:`1424`)
5244

5345
🧐 API and behavior changes
5446
^^^^^^^^^^^^^^^^^^^^^^^^^^^
5547

56-
- :func:`mne_bids.make_dataset_description` will now auto-generate basic ``GeneratedBy`` fields if ``generated_by=None``. To suppress the auto-generated fields, pass an empty list. By `Daniel McCloy`_ (:gh:`1384`)
57-
- Add requirements that ``root``, ``subject``, ``task`` attributes must be set when using :func:`mne_bids.read_raw_bids` to avoid implicit behavior and file ambiguity, by `Teon Brooks`_ (:gh:`1414`)
48+
- None yet
5849

5950
🛠 Requirements
6051
^^^^^^^^^^^^^^^
6152

62-
- MNE-BIDS now requires ``mne`` 1.8 or higher.
53+
- None yet
6354

6455
🪲 Bug fixes
6556
^^^^^^^^^^^^
6657

67-
- :func:`mne_bids.read_raw_bids` can optionally return an ``event_id`` dictionary suitable for use with :func:`mne.events_from_annotations`, and if a ``values`` column is present in ``events.tsv`` it will be used as the source of the integer event ID codes, by `Daniel McCloy`_ (:gh:`1349`)
68-
- BIDS dictates that the recording entity should be displayed as "_recording-" in the filename. This PR makes :class:`mne_bids.BIDSPath` correctly display "_recording-" (instead of "_rec-") in BIDSPath.fpath. By `Scott Huberty`_ (:gh:`1348`)
69-
- :func:`mne_bids.make_dataset_description` now correctly encodes the dataset description as UTF-8 on disk, by `Scott Huberty`_ (:gh:`1357`)
70-
- Corrects extension when filtering filenames in :meth:`mne_bids.BIDSPath.match()` and :func:`mne_bids.find_matching_paths()`, by `Arne Gottwald` (:gh:`1355`)
71-
- Fix :class:`mne_bids.BIDSPath` partially matching a value, by `Pierre Guetschel` (:gh:`1388`)
72-
- Ensures that ``check`` parameter in :meth:`mne_bids.BIDSPath.update()` is passed to :class:`mne_bids.BIDSPath`, by `Teon Brooks`_ (:gh:`1411`)
73-
- minor: added `T2w` to the suffix allowlist, by `Harrison Ritz`_ (:gh:`1420`)
58+
- Fixed a bug that modified the name and help message of some of the available commands, by `Alex Lopez Marquez`_ (:gh:`1441`)
7459

7560
⚕️ Code health
7661
^^^^^^^^^^^^^^
7762

78-
- Tests that were adding or deleting files to/from a session-scoped dataset now properly clean up after themselves, by `Daniel McCloy`_ (:gh:`1347`)
63+
- Made :func:`mne_bids.copyfiles.copyfile_brainvision` output more meaningful error messages when encountering problematic files, by `Stefan Appelhoff`_ (:gh:`1444`)
7964

8065
:doc:`Find out what was new in previous releases <whats_new_previous_releases>`
81-
82-
.. include:: authors.rst

doc/whats_new_previous_releases.rst

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,83 @@
99
What was new in previous releases?
1010
==================================
1111

12+
.. _changes_0_17:
13+
14+
Version 0.17 (2025-09-10)
15+
-------------------------
16+
17+
👩🏽‍💻 Authors
18+
~~~~~~~~~~~~~~~
19+
20+
The following authors contributed for the first time. Thank you so much! 🤩
21+
22+
* `Nathan Azrak`_
23+
* `Matthias Dold`_
24+
* `Berk Gerçek`_
25+
* `Arne Gottwald`_
26+
* `Christian O'Reilly`_
27+
* `Harrison Ritz`_
28+
* `waldie11`_
29+
30+
The following authors had contributed before. Thank you for sticking around! 🤘
31+
32+
* `Stefan Appelhoff`_
33+
* `Teon Brooks`_
34+
* `Pierre Guetschel`_
35+
* `Richard Höchenberger`_
36+
* `Scott Huberty`_
37+
* `Eric Larson`_
38+
* `Daniel McCloy`_
39+
40+
41+
Detailed list of changes
42+
~~~~~~~~~~~~~~~~~~~~~~~~
43+
44+
🚀 Enhancements
45+
^^^^^^^^^^^^^^^
46+
47+
- :func:`mne_bids.write_raw_bids()` can now handle mne `Raw` objects with `eyegaze` and `pupil` channels, by `Christian O'Reilly`_ (:gh:`1344`)
48+
- :func:`mne_bids.get_entity_vals()` has a new parameter ``ignore_suffixes`` to easily ignore sidecar files, by `Daniel McCloy`_ (:gh:`1362`)
49+
- Empty-room matching now preferentially finds recordings in the subject directory tagged as `task-noise` before looking in the `sub-emptyroom` directories. This adds support for a part of the BIDS specification for ER recordings, by `Berk Gerçek`_ (:gh:`1364`)
50+
- Path matching is now implemenented in a more efficient manner within :meth:`mne_bids.BIDSPath.match()` and :func:`mne_bids.find_matching_paths()`, by `Arne Gottwald` (:gh:`1355`)
51+
- :func:`mne_bids.get_entity_vals()` has a new parameter ``include_match`` to prefilter item matching and ignore non-matched items from begin of directory scan, by `Arne Gottwald` (:gh:`1355`)
52+
- Data from ``events.tsv`` can now be read into an OrderedDict using :func:`mne_bids.events_file_to_annotation_kwargs()`, by `Matthias Dold` (:gh:`1389`)
53+
- Read the optionally present extra columns from ``events.tsv`` and pass them to :class:`mne.Annotations`, by `Pierre Guetschel` (:gh:`1401`)
54+
- ``_filter_fnames()`` now correctly checks the default extension, correcting suffix filtering, by `Nathan Azrak` (:gh:`1427`)
55+
56+
57+
🧐 API and behavior changes
58+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
59+
60+
- :func:`mne_bids.make_dataset_description` will now auto-generate basic ``GeneratedBy`` fields if ``generated_by=None``. To suppress the auto-generated fields, pass an empty list. By `Daniel McCloy`_ (:gh:`1384`)
61+
- Add requirements that ``root``, ``subject``, ``task`` attributes must be set when using :func:`mne_bids.read_raw_bids` to avoid implicit behavior and file ambiguity, by `Teon Brooks`_ (:gh:`1414`)
62+
63+
🛠 Requirements
64+
^^^^^^^^^^^^^^^
65+
66+
- MNE-BIDS now requires ``mne`` 1.8 or higher.
67+
68+
🪲 Bug fixes
69+
^^^^^^^^^^^^
70+
71+
- :func:`mne_bids.read_raw_bids` can optionally return an ``event_id`` dictionary suitable for use with :func:`mne.events_from_annotations`, and if a ``values`` column is present in ``events.tsv`` it will be used as the source of the integer event ID codes, by `Daniel McCloy`_ (:gh:`1349`)
72+
- BIDS dictates that the recording entity should be displayed as "_recording-" in the filename. This PR makes :class:`mne_bids.BIDSPath` correctly display "_recording-" (instead of "_rec-") in BIDSPath.fpath. By `Scott Huberty`_ (:gh:`1348`)
73+
- :func:`mne_bids.make_dataset_description` now correctly encodes the dataset description as UTF-8 on disk, by `Scott Huberty`_ (:gh:`1357`)
74+
- Corrects extension when filtering filenames in :meth:`mne_bids.BIDSPath.match()` and :func:`mne_bids.find_matching_paths()`, by `Arne Gottwald` (:gh:`1355`)
75+
- Fix :class:`mne_bids.BIDSPath` partially matching a value, by `Pierre Guetschel` (:gh:`1388`)
76+
- Ensures that ``check`` parameter in :meth:`mne_bids.BIDSPath.update()` is passed to :class:`mne_bids.BIDSPath`, by `Teon Brooks`_ (:gh:`1411`)
77+
- minor: added `T2w` to the suffix allowlist, by `Harrison Ritz`_ (:gh:`1420`)
78+
79+
⚕️ Code health
80+
^^^^^^^^^^^^^^
81+
82+
- Tests that were adding or deleting files to/from a session-scoped dataset now properly clean up after themselves, by `Daniel McCloy`_ (:gh:`1347`)
83+
84+
:doc:`Find out what was new in previous releases <whats_new_previous_releases>`
85+
86+
.. include:: authors.rst
87+
88+
1289
.. _changes_0_16:
1390

1491
Version 0.16 (2024-11-16)

mne_bids/commands/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
mne_bin_dir = Path(mne_bids.__file__).parent
1313
valid_command_paths = sorted((mne_bin_dir / "commands").glob("mne_bids_*.py"))
14-
valid_commands = [cmd.stem.lstrip("mne_bids_") for cmd in valid_command_paths]
14+
valid_commands = [cmd.stem.removeprefix("mne_bids_") for cmd in valid_command_paths]
1515

1616

1717
def print_help():

mne_bids/copyfiles.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,24 @@ def _get_brainvision_paths(vhdr_path):
108108
vmrk_file = vmrk_file_match.groups()[0]
109109

110110
# Make sure we are dealing with file names as is customary, not paths
111-
# Paths are problematic when copying the files to another system. Instead,
112-
# always use the file name and keep the file triplet in the same directory
113-
assert os.sep not in eeg_file
114-
assert os.sep not in vmrk_file
111+
for fi in [eeg_file, vmrk_file]:
112+
if os.sep in fi:
113+
raise RuntimeError(
114+
f"Detected a path separator in a file link: {fi}.\n\n"
115+
"Paths are problematic when copying the files to another system. "
116+
"Instead, always use the file name and keep the "
117+
"BrainVision file triplet (eeg/dat, vhdr, vmrk) in the same directory."
118+
)
115119

116120
# Assert the paths exist
117121
head, tail = op.split(vhdr_path)
118122
eeg_file_path = op.join(head, eeg_file)
119123
vmrk_file_path = op.join(head, vmrk_file)
120-
assert op.exists(eeg_file_path)
121-
assert op.exists(vmrk_file_path)
124+
for fpath in [eeg_file_path, vmrk_file_path]:
125+
if not Path(fpath).exists():
126+
raise FileNotFoundError(
127+
f"{fpath} referenced in {vhdr_path} but it does not exist."
128+
)
122129

123130
# Return the paths
124131
return (eeg_file_path, vmrk_file_path)
@@ -355,14 +362,24 @@ def copyfile_brainvision(vhdr_src, vhdr_dest, anonymize=None, verbose=None):
355362
# Write new header and marker files, fixing the file pointer links
356363
# For that, we need to replace an old "basename" with a new one
357364
# assuming that all .eeg/.dat, .vhdr, .vmrk share one basename
358-
__, basename_src = op.split(fname_src)
359-
assert op.split(eeg_file_path)[-1] in [basename_src + ".eeg", basename_src + ".dat"]
360-
assert basename_src + ".vmrk" == op.split(vmrk_file_path)[-1]
361-
__, basename_dest = op.split(fname_dest)
365+
basename_src = Path(fname_src).name
366+
eeg_expected = [f"{basename_src}.eeg", f"{basename_src}.dat"]
367+
vmrk_expected = [f"{basename_src}.vmrk"]
368+
if Path(eeg_file_path).name not in eeg_expected:
369+
raise RuntimeError(
370+
f"Unexpected path to data file in {vhdr_src}:\n "
371+
f"-->{Path(eeg_file_path).name}\nExpected one of {eeg_expected}."
372+
)
373+
if Path(vmrk_file_path).name not in vmrk_expected:
374+
raise RuntimeError(
375+
f"Unexpected path to marker file in {vhdr_src}:\n "
376+
f"-->{Path(vmrk_file_path).name}\nExpected one of {vmrk_expected}."
377+
)
378+
basename_dest = Path(fname_dest).name
362379
search_lines = [
363-
"DataFile=" + basename_src + ".eeg",
364-
"DataFile=" + basename_src + ".dat",
365-
"MarkerFile=" + basename_src + ".vmrk",
380+
f"DataFile={basename_src}.eeg",
381+
f"DataFile={basename_src}.dat",
382+
f"MarkerFile={basename_src}.vmrk",
366383
]
367384

368385
with open(vhdr_src, encoding=enc) as fin:

mne_bids/dig.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,14 @@ def _write_coordsystem_json(
385385
_write_json(fname, fid_json, overwrite=True)
386386

387387

388-
def _write_dig_bids(bids_path, raw, montage=None, acpc_aligned=False, overwrite=False):
388+
def _write_dig_bids(
389+
bids_path,
390+
raw,
391+
montage=None,
392+
acpc_aligned=False,
393+
electrodes_tsv_task=False,
394+
overwrite=False,
395+
):
389396
"""Write BIDS formatted DigMontage from Raw instance.
390397
391398
Handles coordsystem.json and electrodes.tsv writing
@@ -405,6 +412,9 @@ def _write_dig_bids(bids_path, raw, montage=None, acpc_aligned=False, overwrite=
405412
must be transformed from the "head" coordinate frame.
406413
acpc_aligned : bool
407414
Whether "mri" space is aligned to ACPC.
415+
electrodes_tsv_task : bool
416+
Whether to add the ``task-`` entity to the ``electrodes.tsv`` filename.
417+
Defaults to ``False``.
408418
overwrite : bool
409419
Whether to overwrite the existing file.
410420
Defaults to False.
@@ -500,12 +510,16 @@ def _write_dig_bids(bids_path, raw, montage=None, acpc_aligned=False, overwrite=
500510
"acquisition": bids_path.acquisition,
501511
"space": None if bids_path.datatype == "nirs" else coord_frame,
502512
}
513+
# add `task-` to the electrodes.tsv file if requested
514+
electrode_file_entities = coord_file_entities.copy()
515+
if electrodes_tsv_task and bids_path.task is not None:
516+
electrode_file_entities["task"] = bids_path.task
503517
channels_suffix = "optodes" if bids_path.datatype == "nirs" else "electrodes"
504518
_channels_fun = (
505519
_write_optodes_tsv if bids_path.datatype == "nirs" else _write_electrodes_tsv
506520
)
507521
channels_path = BIDSPath(
508-
**coord_file_entities, suffix=channels_suffix, extension=".tsv"
522+
**electrode_file_entities, suffix=channels_suffix, extension=".tsv"
509523
)
510524
coordsystem_path = BIDSPath(
511525
**coord_file_entities, suffix="coordsystem", extension=".json"

0 commit comments

Comments
 (0)