Commit 7204420f authored by Paul McCarthy's avatar Paul McCarthy 🚵
Browse files

Merge branch 'rel/3.0.1' into 'v3.0'

Rel/3.0.1

See merge request fsl/fslpy!225
parents 537dec2e 776ec115
Pipeline #5220 passed with stages
in 7 minutes and 13 seconds
......@@ -206,7 +206,7 @@ build-doc:
- docker
stage: doc
image: python:3.6
image: python:3.7
script:
- bash ./.ci/build_doc.sh
......@@ -227,7 +227,7 @@ build-pypi-dist:
<<: *check_version
stage: build
image: python:3.6
image: python:3.7
tags:
- docker
......@@ -251,7 +251,7 @@ deploy-doc:
<<: *setup_ssh
stage: deploy
when: manual
image: python:3.6
image: python:3.7
tags:
- docker
......@@ -268,7 +268,7 @@ deploy-pypi:
<<: *setup_ssh
stage: deploy
when: manual
image: python:3.6
image: python:3.7
tags:
- docker
......@@ -285,7 +285,7 @@ deploy-zenodo:
<<: *setup_ssh
stage: deploy
when: manual
image: python:3.6
image: python:3.7
tags:
- docker
......
......@@ -2,6 +2,17 @@ This document contains the ``fslpy`` release history in reverse chronological
order.
3.0.1 (Wednesday 15th April 2020)
---------------------------------
Changed
^^^^^^^
* The :func:`.isMelodicDir` function now accepts directories that do not end
with ``.ica``, as long as all required files are present.
3.0.0 (Sunday 29th March 2020)
------------------------------
......@@ -52,7 +63,7 @@ Changed
:attr:`.LOAD` symbol, can now be accessed as attributes of the returned
results object, in addition to being accessed as dict items.
* Wrapper functions decorated with the :func:`.fileOrImage`,
:func:`.fileOrArray`, or :func:`.fileOrText` decorators will now pass all
:func:`.fileOrArray`, or :func:`.fileOrText` decorators will now pass all
arguments and return values through unchanged if an argument called ``submit``
is passed in, and is set to ``True`` (or any non-``False``
value). Furthermore, in such a scenario a :exc:`ValueError` will be raised if
......
......@@ -622,8 +622,9 @@ class Nifti(notifier.Notifier, meta.Meta):
if from_ not in ('voxel', 'fsl', 'world') or \
to not in ('voxel', 'fsl', 'world'):
raise ValueError('Invalid source/reference spaces: '
'{} -> {}'.format(from_, to))
raise ValueError('Invalid source/reference spaces: "{}" -> "{}".'
'Recognised spaces are "voxel", "fsl", and '
'"world"'.format(from_, to))
return np.copy(self.__affines[from_, to])
......
......@@ -33,7 +33,6 @@ import logging
import os.path as op
import numpy as np
import fsl.utils.path as fslpath
import fsl.data.image as fslimage
import fsl.data.featanalysis as featanalysis
......@@ -63,10 +62,9 @@ def isMelodicImage(path):
def isMelodicDir(path):
"""Returns ``True`` if the given path looks like it is contained within
a MELODIC directory, ``False`` otherwise. A melodic directory:
"""Returns ``True`` if the given path looks like it is a MELODIC directory,
``False`` otherwise. A MELODIC directory:
- Must be named ``*.ica``.
- Must contain a file called ``melodic_IC.nii.gz`` or
``melodic_oIC.nii.gz``.
- Must contain a file called ``melodic_mix``.
......@@ -75,12 +73,7 @@ def isMelodicDir(path):
path = op.abspath(path)
if op.isdir(path): dirname = path
else: dirname = op.dirname(path)
sufs = ['.ica']
if not any([dirname.endswith(suf) for suf in sufs]):
if not op.isdir(path):
return False
# Must contain an image file called
......@@ -88,7 +81,7 @@ def isMelodicDir(path):
prefixes = ['melodic_IC', 'melodic_oIC']
for p in prefixes:
try:
fslimage.addExt(op.join(dirname, p))
fslimage.addExt(op.join(path, p))
break
except fslimage.PathError:
pass
......@@ -97,8 +90,8 @@ def isMelodicDir(path):
# Must contain files called
# melodic_mix and melodic_FTmix
if not op.exists(op.join(dirname, 'melodic_mix')): return False
if not op.exists(op.join(dirname, 'melodic_FTmix')): return False
if not op.exists(op.join(path, 'melodic_mix')): return False
if not op.exists(op.join(path, 'melodic_FTmix')): return False
return True
......@@ -108,10 +101,13 @@ def getAnalysisDir(path):
to that MELODIC directory is returned. Otherwise, ``None`` is returned.
"""
meldir = fslpath.deepest(path, ['.ica'])
if not op.isdir(path):
path = op.dirname(path)
if meldir is not None and isMelodicDir(meldir):
return meldir
while path not in (op.sep, ''):
if isMelodicDir(path):
return path
path = op.dirname(path)
return None
......
......@@ -47,7 +47,7 @@ import re
import string
__version__ = '3.0.0'
__version__ = '3.0.1'
"""Current version number, as a string. """
......
......@@ -98,19 +98,26 @@ def invxfm(inmat, omat):
return ['convert_xfm', '-omat', omat, '-inverse', inmat]
@wutils.fileOrArray('inmat1', 'inmat2', 'outmat')
@wutils.fileOrArray('atob', 'atoc', 'btoc')
@wutils.fslwrapper
def concatxfm(inmat1, inmat2, outmat):
"""Use ``convert_xfm`` to concatenate two affines."""
def concatxfm(atob, btoc, atoc):
"""Use ``convert_xfm`` to concatenate two affines. Note that the
order of the input matrices is the opposite of the order expected
by ``convert_xfm``.
:arg atob: Input matrix, transforming from "A" to "B".
:arg btoc: Input matrix, transforming from "B" to "C".
:arg atoc: Output matrix, transforming from "A" to "C".
"""
asrt.assertFileExists(inmat1, inmat2)
asrt.assertFileExists(atob, btoc)
cmd = ['convert_xfm',
'-omat',
outmat,
atoc,
'-concat',
inmat2,
inmat1]
btoc,
atob]
return cmd
......
......@@ -160,14 +160,14 @@ def test_assertIsMelodicDir():
('analysis.ica', [ 'melodic_mix', 'melodic_FTmix'], False),
('analysis.ica', ['melodic_IC.nii.gz', 'melodic_FTmix'], False),
('analysis.ica', ['melodic_IC.nii.gz', 'melodic_mix'], False),
('analysis', ['melodic_IC.nii.gz', 'melodic_mix', 'melodic_FTmix'], False),
('analysis', ['melodic_oIC.nii.gz', 'melodic_mix', 'melodic_FTmix'], False),
('analysis', ['melodic_IC.nii.gz', 'melodic_mix', 'melodic_FTmix'], True),
('analysis', [ 'melodic_mix', 'melodic_FTmix'], False),
]
for dirname, paths, expected in tests:
with testdir(paths, dirname):
if expected:
assertions.assertIsMelodicDir(dirname)
assertions.assertIsMelodicDir('.')
else:
with pytest.raises(AssertionError):
assertions.assertIsMelodicDir(dirname)
......
......@@ -13,7 +13,8 @@ import os
import os.path as op
import numpy as np
import mock
from unittest import mock
import pytest
import tests
......
......@@ -22,7 +22,7 @@ from . import mockFSLDIR
mock_fsl_sub = """
#!{}
#!/usr/bin/env python3
import random
import os
......@@ -62,8 +62,7 @@ with open('{{}}.o{{}}'.format(cmd, jobid), 'w') as stdout, \
print(str(jobid))
sys.exit(0)
""".format(sys.executable, op.dirname(fsl.__file__)).strip()
""".format(op.dirname(fsl.__file__)).strip()
@contextlib.contextmanager
def fslsub_mockFSLDIR():
......
......@@ -55,10 +55,10 @@ def test_isMelodicDir():
meldir = op.join(testdir, 'analysis.ica')
assert mela.isMelodicDir(meldir)
# Directory must end in .ica
# non-.ica prefix is ok
with tests.testdir([p.replace('.ica', '.blob') for p in paths]) as testdir:
meldir = op.join(testdir, 'analysis.blob')
assert not mela.isMelodicDir(meldir)
assert mela.isMelodicDir(meldir)
# Directory must exist!
assert not mela.isMelodicDir('non-existent.ica')
......
......@@ -18,9 +18,9 @@ from .. import mockFSLDIR as mockFSLDIR_base, make_random_image
mock_fslstats = """
#!{}
#!/usr/bin/env python3
shape = {{outshape}}
shape = {outshape}
import sys
import numpy as np
......@@ -31,7 +31,7 @@ if len(shape) == 1:
data = data.reshape(1, -1)
np.savetxt(sys.stdout, data, fmt='%i')
""".format(sys.executable).strip()
""".strip()
@contextlib.contextmanager
......
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