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

[WIP] : simplify fpath #721

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
86 changes: 38 additions & 48 deletions mne_bids/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,10 @@ class BIDSPath(object):
The "data type" of folder being created at the end of the folder
hierarchy. E.g., ``'anat'``, ``'func'``, ``'eeg'``, ``'meg'``,
``'ieeg'``, etc.
root : str | pathlib.Path | None
root : str | pathlib.Path
The root for the filename to be created. E.g., a path to the folder
in which you wish to create a file with this name.
Defaults to ``'.'``.
adam2392 marked this conversation as resolved.
Show resolved Hide resolved
check : bool
If True enforces the entities to be valid according to the
current BIDS standard. Defaults to True.
Expand Down Expand Up @@ -227,7 +228,7 @@ class BIDSPath(object):
Examples
--------
>>> bids_path = BIDSPath(subject='test', session='two', task='mytask',
suffix='ieeg', extension='.edf')
suffix='ieeg', extension='.edf')
>>> print(bids_path.basename)
sub-test_ses-two_task-mytask_ieeg.edf
>>> bids_path
Expand Down Expand Up @@ -261,7 +262,7 @@ class BIDSPath(object):

def __init__(self, subject=None, session=None,
task=None, acquisition=None, run=None, processing=None,
recording=None, space=None, split=None, root=None,
recording=None, space=None, split=None, root='.',
suffix=None, extension=None, datatype=None, check=True):
if all(ii is None for ii in [subject, session, task,
acquisition, run, processing,
Expand Down Expand Up @@ -409,6 +410,8 @@ def fpath(self):
# get the inner-most BIDS directory for this file path
data_path = self.directory

assert self.root is not None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could make use of MNE's _validate_type()


# account for MEG data that are directory-based
# else, all other file paths attempt to match
if self.suffix == 'meg' and self.extension == '.ds':
Expand All @@ -420,54 +423,41 @@ def fpath(self):
# if suffix and/or extension is missing, and root is
# not None, then BIDSPath will infer the dataset
# else, return the relative path with the basename
if (self.suffix is None or self.extension is None) and \
self.root is not None:
# get matching BIDS paths inside the bids root
matching_paths = \
_get_matching_bidspaths_from_filesystem(self)

# FIXME This will break
# FIXME e.g. with FIFF data split across multiple files.
# if extension is not specified and no unique file path
# return filepath of the actual dataset for MEG/EEG/iEEG data
if self.suffix is None or self.suffix in ALLOWED_DATATYPES:
# now only use valid datatype extension
valid_exts = sum(ALLOWED_DATATYPE_EXTENSIONS.values(), [])
matching_paths = [p for p in matching_paths
if _parse_ext(p)[1] in valid_exts]

if (self.split is None and
(not matching_paths or
'_split-' in matching_paths[0])):
# try finding FIF split files (only first one)
this_self = self.copy().update(split='01')
matching_paths = \
_get_matching_bidspaths_from_filesystem(this_self)

# found no matching paths
if not matching_paths:
msg = (f'Could not locate a data file of a supported '
f'format. This is likely a problem with your '
f'BIDS dataset. Please run the BIDS validator '
f'on your data. (root={self.root}, '
f'basename={self.basename}). '
f'{matching_paths}')
warn(msg)

bids_fpath = op.join(data_path, self.basename)
# if paths still cannot be resolved, then there is an error
elif len(matching_paths) > 1:
msg = ('Found more than one matching data file for the '
'requested recording. Cannot proceed due to the '
'ambiguity. This is likely a problem with your '
'BIDS dataset. Please run the BIDS validator on '
'your data.')
raise RuntimeError(msg)
else:
bids_fpath = matching_paths[0]
# get matching BIDS paths inside the bids root
matching_paths = \
_get_matching_bidspaths_from_filesystem(self)

# FIXME This will break
# FIXME e.g. with FIFF data split across multiple files.
# if extension is not specified and no unique file path
# return filepath of the actual dataset for MEG/EEG/iEEG data
if self.suffix is None or self.suffix in ALLOWED_DATATYPES:
# now only use valid datatype extension
valid_exts = sum(ALLOWED_DATATYPE_EXTENSIONS.values(), [])
matching_paths = [p for p in matching_paths
if _parse_ext(p)[1] in valid_exts]

if (self.split is None and self.suffix is None and
self.extension is None and
(not matching_paths or
'_split-' in matching_paths[0])):
# try finding FIF split files (only first one)
this_self = self.copy().update(split='01')
matching_paths = \
_get_matching_bidspaths_from_filesystem(this_self)

else:
if not matching_paths: # found no matching paths
bids_fpath = op.join(data_path, self.basename)
elif len(matching_paths) > 1:
msg = ('Found more than one matching data file for the '
'requested recording. Cannot proceed due to the '
'ambiguity. This is likely a problem with your '
'BIDS dataset. Please run the BIDS validator on '
'your data.')
raise RuntimeError(msg)
else:
bids_fpath = matching_paths[0]

bids_fpath = Path(bids_fpath)
return bids_fpath
Expand Down
26 changes: 14 additions & 12 deletions mne_bids/tests/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,15 +365,15 @@ def test_bids_path_inference(return_bids_test_dir):
with pytest.raises(RuntimeError, match='Found more than one'):
bids_path.fpath

# can't locate a file, but the basename should work
bids_path = BIDSPath(
subject=subject_id, session=session_id, acquisition=acq,
task=task, run='10', root=bids_root)
with pytest.warns(RuntimeWarning, match='Could not locate'):
fpath = bids_path.fpath
assert str(fpath) == op.join(bids_root, f'sub-{subject_id}',
f'ses-{session_id}',
bids_path.basename)
# # can't locate a file, but the basename should work
# bids_path = BIDSPath(
# subject=subject_id, session=session_id, acquisition=acq,
# task=task, run='10', root=bids_root)
# with pytest.warns(RuntimeWarning, match='Could not locate'):
# fpath = bids_path.fpath
# assert str(fpath) == op.join(bids_root, f'sub-{subject_id}',
# f'ses-{session_id}',
# bids_path.basename)

# shouldn't error out when there is no uncertainty
channels_fname = BIDSPath(subject=subject_id, session=session_id,
Expand Down Expand Up @@ -404,9 +404,11 @@ def test_bids_path(return_bids_test_dir):
"""Test usage of BIDSPath object."""
bids_root = return_bids_test_dir

bids_path = BIDSPath(
bids_path_kwargs = dict(
subject=subject_id, session=session_id, run=run, acquisition=acq,
task=task, root=bids_root, suffix='meg')
task=task, suffix='meg'
)
bids_path = BIDSPath(root=bids_root, **bids_path_kwargs)

expected_parent_dir = op.join(bids_root, f'sub-{subject_id}',
f'ses-{session_id}', 'meg')
Expand All @@ -420,7 +422,7 @@ def test_bids_path(return_bids_test_dir):
assert op.dirname(bids_path.fpath).startswith(bids_root)

# when bids root is not passed in, passes relative path
bids_path2 = bids_path.copy().update(datatype='meg', root=None)
bids_path2 = BIDSPath(datatype='meg', **bids_path_kwargs)
expected_relpath = op.join(
f'sub-{subject_id}', f'ses-{session_id}', 'meg',
expected_basename + '_meg')
Expand Down