Commit 3c57660e authored by Paul McCarthy's avatar Paul McCarthy 🚵
Browse files

Merge branch 'rf/bids' into 'master'

Rf/bids

See merge request fsl/fslpy!287
parents 33f85a0a 02a84b76
......@@ -13,6 +13,8 @@ Changed
* The :class:`.TaskThread` now allows an error handler function to be
specified, which is run on the :mod:`.idle` loop.
* The :func:`.bids.loadMetadata` function no long resolves sym-links when
determining whether a file is contained within a BIDS data set.
Deprecated
......
......@@ -18,6 +18,7 @@
All of the other functions in this module should not be considered part of the
public API.
.. see:: https://bids-specification.readthedocs.io/en/stable/
.. note:: The `pybids <https://bids-standard.github.io/pybids/>`_ library is
a more suitable choice if you are after a more robust and featured
......@@ -36,8 +37,8 @@ import fsl.utils.path as fslpath
class BIDSFile(object):
"""The ``BIDSFile`` class parses and stores the entities and suffix contained
in a BIDS file. See the :func:`parseFilename` function.
"""The ``BIDSFile`` class parses and stores the entities and suffix
contained in a BIDS file. See the :func:`parseFilename` function.
The :meth:`match` method can be used to compare two ``BIDSFile`` instances.
......@@ -91,15 +92,9 @@ class BIDSFile(object):
def parseFilename(filename):
"""Parses a BIDS-like file name. The file name must consist of zero or more
"entities" (alpha-numeric ``name-value`` pairs), a "suffix", all separated
by underscores, and a regular file extension. For example, the following
file::
sub-01_ses-01_task-stim_bold.nii.gz
has suffix ``bold``, entities ``sub=01``, ``ses=01`` and ``task=stim``, and
extension ``.nii.gz``.
"""Parses a BIDS-like file name, returning the entities and suffix encoded
in the name. See the :func:`isBIDSFile` function for an explanation of
what is considered to be a valid BIDS file name.
.. note:: This function assumes that no period (``.``) characters occur in
the body of a BIDS filename.
......@@ -161,11 +156,24 @@ def inBIDSDir(filename):
def isBIDSFile(filename, strict=True):
"""Returns ``True`` if ``filename`` looks like a BIDS image or JSON file.
A BIDS file name must consist of zero or more "entities" (alpha-numeric
``name-value`` pairs), a "suffix", all separated by underscores, and a
regular file extension. For example, the following file::
sub-01_ses-01_task-stim_bold.nii.gz
has suffix ``bold``, entities ``sub=01``, ``ses=01`` and ``task=stim``, and
extension ``.nii.gz``.
:arg filename: Name of file to check
:arg strict: If ``True`` (the default), the file must be within a BIDS
dataset directory, as defined by :func:`inBIDSDir`.
"""
# Zero or more entities because sidecar files
# do not necessarily need to contain any
# entities (e.g. ``T1w.json`` is valid)
name = op.basename(filename)
pattern = r'([a-z0-9]+-[a-z0-9]+_)*([a-z0-9])+\.(.+)'
flags = re.ASCII | re.IGNORECASE
......@@ -189,7 +197,7 @@ def loadMetadata(filename):
``filename``
"""
filename = op.realpath(op.abspath(filename))
filename = op.abspath(filename)
bfile = BIDSFile(filename)
dirname = op.dirname(filename)
prevdir = filename
......
......@@ -18,8 +18,11 @@ import fsl.utils.bids as fslbids
def test_parseFilename():
badtests = ['bad_file.txt']
for test in badtests:
with pytest.raises(ValueError):
fslbids.parseFilename('bad_file.txt')
fslbids.parseFilename(test)
tests = [
('sub-01_ses-01_t1w.nii.gz',
......@@ -105,3 +108,41 @@ def test_loadMetadata():
assert fslbids.loadMetadata(t1) == {**meta2, **meta1}
json4.write_text(json.dumps(meta4))
assert fslbids.loadMetadata(t1) == {**meta4, **meta2, **meta1}
def test_loadMetadata_symlinked():
ddreal = Path('a')
t1real = Path('b')
j1real = Path('c')
j2real = Path('d')
j3real = Path('e')
j4real = Path('f')
dd = Path('data/dataset_description.json')
t1 = Path('data/sub-01/func/sub-01_task-stim_bold.nii.gz')
json1 = Path('data/sub-01/func/sub-01_task-stim_bold.json')
json2 = Path('data/sub-01/sub-01_bold.json')
json3 = Path('data/sub-01_t1w.json')
json4 = Path('data/sub-01/task-stim_bold.json')
meta1 = {'a' : '1', 'b' : '2'}
meta2 = {'a' : '10', 'c' : '3'}
meta3 = {'a' : '109', 'b' : '99'}
meta4 = {'c' : '9', 'd' : '5'}
with tempdir():
ddreal.touch()
t1real.touch()
j1real.write_text(json.dumps(meta1))
j2real.write_text(json.dumps(meta2))
j3real.write_text(json.dumps(meta3))
j4real.write_text(json.dumps(meta4))
Path(op.dirname(t1)).mkdir(parents=True)
dd .symlink_to(op.join('..', ddreal))
t1 .symlink_to(op.join('..', '..', '..', t1real))
json1.symlink_to(op.join('..', '..', '..', j1real))
json2.symlink_to(op.join('..', '..', j2real))
json3.symlink_to(op.join('..', j3real))
json4.symlink_to(op.join('..', '..', j4real))
assert fslbids.loadMetadata(t1) == {**meta4, **meta2, **meta1}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment