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

[MRG] Suggest alternatives when value not found in list #1066

Merged
merged 4 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Detailed list of changes

- :func:`~mne_bids.write_raw_bids` now supports EGI format, by `Anand Saini`_, `Scott Huberty`_ and `Mathieu Scheltienne`_ (:gh:`1006`)

- When a given subject cannot be found, valid suggestions are now printed, by `Eric Larson`_ (:gh:`1066`)

- TSV files that are empty (i.e., only a header row is present) are now handled more robustly and a warning is issued, by `Stefan Appelhoff`_ (:gh:`1038`)

🧐 API and behavior changes
Expand Down
22 changes: 19 additions & 3 deletions mne_bids/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import json
import re
from datetime import datetime, timezone
from difflib import get_close_matches

import numpy as np
import mne
Expand Down Expand Up @@ -182,10 +183,24 @@ def _read_events(events, event_id, raw, bids_path=None):
return all_events, all_dur, all_desc


def _verbose_list_index(lst, val, *, allow_all=False):
# try to "return lst.index(val)" for list of str, but be more
# informative/verbose when it fails
try:
return lst.index(val)
except ValueError as exc:
# Use str cast here to deal with pathlib.Path instances
extra = get_close_matches(str(val), [str(ll) for ll in lst])
if allow_all and not extra:
extra = lst
extra = f'. Did you mean one of {extra}?' if extra else ''
raise ValueError(f'{exc}{extra}') from None


def _handle_participants_reading(participants_fname, raw, subject):
participants_tsv = _from_tsv(participants_fname)
subjects = participants_tsv['participant_id']
row_ind = subjects.index(subject)
row_ind = _verbose_list_index(subjects, subject, allow_all=True)
raw.info['subject_info'] = dict() # start from scratch

# set data from participants tsv into subject_info
Expand Down Expand Up @@ -250,7 +265,7 @@ def _handle_scans_reading(scans_fname, raw, bids_path):
if all(suffix in ('.vhdr', '.eeg', '.vmrk') for suffix in acq_suffixes):
ext = fnames[0].suffix
data_fname = Path(data_fname).with_suffix(ext)
row_ind = fnames.index(data_fname)
row_ind = _verbose_list_index(fnames, data_fname)

# check whether all split files have the same acq_time
# and throw an error if they don't
Expand All @@ -265,7 +280,8 @@ def _handle_scans_reading(scans_fname, raw, bids_path):
))
split_acq_times = []
for split_f in split_fnames:
split_acq_times.append(acq_times[fnames.index(split_f)])
split_acq_times.append(
acq_times[_verbose_list_index(fnames, split_f)])
if len(set(split_acq_times)) != 1:
raise ValueError("Split files must have the same acq_time.")

Expand Down