Skip to content
Snippets Groups Projects
Commit 3b1caaeb authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

Merge branch 'enh/pathutils' into 'master'

Enh/pathutils

See merge request fsl/fslpy!247
parents 29e59f44 898176f8
No related branches found
No related tags found
No related merge requests found
Pipeline #5577 passed
Showing
with 736 additions and 101 deletions
......@@ -2,6 +2,25 @@ This document contains the ``fslpy`` release history in reverse chronological
order.
3.3.0 (Under development)
-------------------------
Added
^^^^^
* New ported versions of various core FSL tools, including ``imrm``, ``imln``,
``imtest``, ``fsl_abspath``, ``remove_ext``, ``Text2Vest``, and
``Vest2Text``.
Changed
^^^^^^^
* Adjustments to tests and documentation
3.2.2 (Thursday 9th July 2020)
------------------------------
......
......@@ -1625,18 +1625,20 @@ def removeExt(filename):
return fslpath.removeExt(filename, ALLOWED_EXTENSIONS)
def fixExt(filename):
def fixExt(filename, **kwargs):
"""Fix the extension of ``filename``.
For example, if a file name is passed in as ``file.nii.gz``, but the
file is actually ``file.nii``, this function will fix the file name.
If ``filename`` already exists, it is returned unchanged.
All other arguments are passed through to :func:`addExt`.
"""
if op.exists(filename):
return filename
else:
return addExt(removeExt(filename))
return addExt(removeExt(filename), **kwargs)
def defaultExt():
......
......@@ -11,9 +11,14 @@
looksLikeVestLutFile
loadVestLutFile
loadVestFile
generateVest
"""
import textwrap as tw
import io
import numpy as np
......@@ -76,3 +81,70 @@ def loadVestLutFile(path, normalise=True):
else:
return colours
def loadVestFile(path, ignoreHeader=True):
"""Loads numeric data from a VEST file, returning it as a ``numpy`` array.
:arg ignoreHeader: if ``True`` (the default), the matrix shape specified
in the VEST header information is ignored, and the shape
inferred from the data. Otherwise, if the number of
rows/columns specified in the VEST header information
does not match the matrix shape, a ``ValueError`` is
raised.
:returns: a ``numpy`` array containing the matrix data in the
VEST file.
"""
data = np.loadtxt(path, comments=['#', '/'])
if not ignoreHeader:
nrows, ncols = None, None
with open(path, 'rt') as f:
for line in f:
if 'NumWaves' in line: ncols = int(line.split()[1])
elif 'NumPoints' in line: nrows = int(line.split()[1])
else: continue
if (ncols is not None) and (nrows is not None):
break
if tuple(data.shape) != (nrows, ncols):
raise ValueError(f'Invalid VEST file ({path}) - data shape '
f'({data.shape}) does not match header '
f'({nrows}, {ncols})')
return data
def generateVest(data):
"""Generates VEST-formatted text for the given ``numpy`` array.
:arg data: A 1D or 2D numpy array.
:returns: A string containing a VEST header, and the ``data``.
"""
data = np.asanyarray(data)
if len(data.shape) not in (1, 2):
raise ValueError(f'unsupported number of dimensions: {data.shape}')
data = np.atleast_2d(data)
if np.issubdtype(data.dtype, np.integer): fmt = '%d'
else: fmt = '%0.12f'
sdata = io.StringIO()
np.savetxt(sdata, data, fmt=fmt)
sdata = sdata.getvalue()
nrows, ncols = data.shape
vest = tw.dedent(f"""
/NumWaves {ncols}
/NumPoints {nrows}
/Matrix
""").strip() + '\n' + sdata
return vest.strip()
#!/usr/bin/env python
#
# Text2Vest.py - Convert an ASCII text matrix file into a VEST file.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""``Text2Vest`` simply takes a plain text ASCII text matrix file, and
adds a VEST header.
"""
import sys
import numpy as np
import fsl.data.vest as fslvest
usage = "Usage: Text2Vest <text_file> <vest_file>"
def main(argv=None):
"""Convert a plain text file to a VEST file. """
if argv is None:
argv = sys.argv[1:]
if len(argv) != 2:
print(usage)
return 0
infile, outfile = argv
data = np.loadtxt(infile)
vest = fslvest.generateVest(data)
with open(outfile, 'wt') as f:
f.write(vest)
return 0
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python
#
# Vest2Text.py - Convert a VEST matrix file into a plain text ASCII file.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""``Vest2Text`` takes a VEST file containing a 2D matrix, and converts it
into a plain-text ASCII file.
"""
import sys
import numpy as np
import fsl.data.vest as fslvest
usage = "Usage: Vest2Text <vest_file> <text_file>"
def main(argv=None):
"""Convert a VEST file to a plain text file. """
if argv is None:
argv = sys.argv[1:]
if len(argv) != 2:
print(usage)
return 0
infile, outfile = argv
data = fslvest.loadVestFile(infile)
if np.issubdtype(data.dtype, np.integer): fmt = '%d'
else: fmt = '%0.12f'
np.savetxt(outfile, data, fmt=fmt)
return 0
if __name__ == '__main__':
sys.exit(main())
......@@ -5,5 +5,12 @@
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""The ``fsl.scripts`` package contains all of the executable scripts provided
by ``fslpy``.
by ``fslpy``, and other python-based FSL packages.
.. note:: The ``fsl.scripts`` namespace is a ``pkgutil``-style *namespace
package* - it can be used across different projects - see
https://packaging.python.org/guides/packaging-namespace-packages/ for
details.
"""
__path__ = __import__('pkgutil').extend_path(__path__, __name__) # noqa
#!/usr/bin/env python
#
# fsl_abspath.py - Make a path absolute
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""The fsl_abspath command - makes relative paths absolute.
"""
import os.path as op
import sys
usage = """
usage: fsl_abspath path
""".strip()
def main(argv=None):
"""fsl_abspath - make a relative path absolute. """
if argv is None:
argv = sys.argv[1:]
if len(argv) != 1:
print(usage)
return 1
print(op.realpath(argv[0]))
return 0
if __name__ == '__main__':
sys.exit(main())
......@@ -9,8 +9,6 @@ time series from a MELODIC ``.ica`` directory.
"""
from __future__ import print_function
import os.path as op
import sys
import argparse
......
......@@ -12,8 +12,6 @@ The :func:`main` function is essentially a wrapper around the
"""
from __future__ import print_function
import os.path as op
import sys
import warnings
......
......@@ -9,8 +9,6 @@ NIFTI/ANALYZE image files.
"""
from __future__ import print_function
import sys
import warnings
import fsl.utils.path as fslpath
......
#!/usr/bin/env python
#
# imln.py - Create symbolic links to image files.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module defines the ``imln`` application, for creating sym-links
to NIFTI image files.
.. note:: When creating links to relative paths, ln requires that the path is
relative to the link location, rather than the invocation
location. This is *not* currently supported by imln, and possibly
never will be.
"""
import os.path as op
import os
import sys
import warnings
import fsl.utils.path as fslpath
# See atlasq.py for explanation
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=FutureWarning)
import fsl.data.image as fslimage
ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
"""List of file extensions that are supported by ``imln``. """
usage = """
Usage: imln <file1> <file2>
Makes a link (called file2) to file1
NB: filenames can be basenames or include an extension
""".strip()
def main(argv=None):
"""``imln`` - create sym-links to images. """
if argv is None:
argv = sys.argv[1:]
if len(argv) != 2:
print(usage)
return 1
target, linkbase = argv
target = fslpath.removeExt(target, ALLOWED_EXTENSIONS)
linkbase = fslpath.removeExt(linkbase, ALLOWED_EXTENSIONS)
# Target must exist, so we can
# infer the correct extension(s).
# Error on incomplete file groups
# (e.g. a.img without a.hdr).
try:
targets = fslpath.getFileGroup(target,
allowedExts=ALLOWED_EXTENSIONS,
fileGroups=fslimage.FILE_GROUPS,
unambiguous=True)
except Exception as e:
print(f'Error: {e}')
return 1
for target in targets:
if not op.exists(target):
continue
ext = fslpath.getExt(target, ALLOWED_EXTENSIONS)
link = f'{linkbase}{ext}'
try:
# emulate old imln behaviour - if
# link already exists, it is removed
if op.exists(link):
os.remove(link)
os.symlink(target, link)
except Exception as e:
print(f'Error: {e}')
return 1
return 0
if __name__ == '__main__':
sys.exit(main())
......@@ -13,8 +13,6 @@ The :func:`main` function is essentially a wrapper around the
"""
from __future__ import print_function
import os.path as op
import sys
import warnings
......
#!/usr/bin/env python
#
# imrm.py - Remove image files.
#
# Author: Paul McCarthy <paulmc@fmrib.ox.ac.uk>
#
"""This module defines the ``imrm`` application, for removing NIFTI image
files.
"""
import itertools as it
import os.path as op
import os
import sys
import warnings
import fsl.utils.path as fslpath
# See atlasq.py for explanation
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=FutureWarning)
import fsl.data.image as fslimage
usage = """Usage: imrm <list of image names to remove>
NB: filenames can be basenames or not
""".strip()
ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
"""List of file extensions that are removed by ``imrm``. """
def main(argv=None):
"""Removes all images which are specified on the command line. """
if argv is None:
argv = sys.argv[1:]
if len(argv) < 1:
print(usage)
return 1
prefixes = [fslpath.removeExt(p, ALLOWED_EXTENSIONS) for p in argv]
for prefix, ext in it.product(prefixes, ALLOWED_EXTENSIONS):
path = f'{prefix}{ext}'
if op.exists(path):
os.remove(path)
return 0
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python
#
# imtest.py - Test whether an image file exists or not.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""The ``imtest`` script can be used to test whether an image file exists or
not, without having to know the file suffix (.nii, .nii.gz, etc).
"""
import os.path as op
import sys
import warnings
import fsl.utils.path as fslpath
# See atlasq.py for explanation
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=FutureWarning)
import fsl.data.image as fslimage
ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
"""List of file extensions that are supported by ``imln``. """
def main(argv=None):
"""Test if an image path exists, and prints ``'1'`` if it does or ``'0'``
if it doesn't.
"""
if argv is None:
argv = sys.argv[1:]
# emulate old fslio/imtest - always return 0
if len(argv) != 1:
print('0')
return 0
path = fslpath.removeExt(argv[0], ALLOWED_EXTENSIONS)
path = op.realpath(path)
# getFileGroup will raise an error
# if the image (including all
# components - i.e. header and
# image) does not exist
try:
fslpath.getFileGroup(path,
allowedExts=ALLOWED_EXTENSIONS,
fileGroups=fslimage.FILE_GROUPS,
unambiguous=True)
print('1')
except fslpath.PathError:
print('0')
return 0
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python
#
# remove_ext.py - Remove file extensions from NIFTI image paths
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import sys
import warnings
import fsl.utils.path as fslpath
# See atlasq.py for explanation
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=FutureWarning)
import fsl.data.image as fslimage
usage = """Usage: remove_ext <list of image paths to remove extension from>
""".strip()
ALLOWED_EXTENSIONS = fslimage.ALLOWED_EXTENSIONS + ['.mnc', '.mnc.gz']
"""List of file extensions that are removed by ``remove_ext``. """
def main(argv=None):
"""Removes file extensions from all paths which are specified on the
command line.
"""
if argv is None:
argv = sys.argv[1:]
if len(argv) < 1:
print(usage)
return 1
removed = []
for path in argv:
removed.append(fslpath.removeExt(path, ALLOWED_EXTENSIONS))
print(' '.join(removed))
return 0
if __name__ == '__main__':
sys.exit(main())
......@@ -118,9 +118,16 @@ setup(
entry_points={
'console_scripts' : [
'immv = fsl.scripts.immv:main',
'imcp = fsl.scripts.imcp:main',
'imln = fsl.scripts.imln:main',
'immv = fsl.scripts.immv:main',
'imrm = fsl.scripts.imrm:main',
'imglob = fsl.scripts.imglob:main',
'imtest = fsl.scripts.imtest:main',
'remove_ext = fsl.scripts.remove_ext:main',
'fsl_abspath = fsl.scripts.fsl_abspath:main',
'Text2Vest = fsl.scripts.Text2Vest:main',
'Vest2Text = fsl.scripts.Vest2Text:main',
'atlasq = fsl.scripts.atlasq:main',
'atlasquery = fsl.scripts.atlasq:atlasquery_emulation',
'fsl_ents = fsl.scripts.fsl_ents:main',
......
#!/usr/bin/env python
#
# test_imglob.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import pytest
import fsl.scripts.imglob as imglob
from . import testdir
def test_imglob_shouldPass():
# (files to create, paths, output, expected)
tests = [
# normal usage, one file
('file.hdr file.img', 'file', None, 'file'),
('file.hdr file.img', 'file', 'prefix', 'file'),
('file.hdr file.img', 'file', 'primary', 'file.hdr'),
('file.hdr file.img', 'file', 'all', 'file.hdr file.img'),
# incomplete file pair
('file.hdr', 'file', 'prefix', 'file'),
('file.hdr', 'file.hdr', 'prefix', 'file'),
('file.hdr', 'file.img', 'prefix', 'file'),
('file.hdr', 'file', 'primary', 'file.hdr'),
('file.hdr', 'file.hdr', 'primary', 'file.hdr'),
('file.hdr', 'file.img', 'primary', 'file.hdr'),
('file.hdr', 'file', 'all', 'file.hdr'),
('file.hdr', 'file.hdr', 'all', 'file.hdr'),
('file.hdr', 'file.img', 'all', 'file.hdr'),
# same file specified multiple times
('file.hdr file.img', 'file file', 'prefix', 'file'),
('file.hdr file.img', 'file file.img', 'prefix', 'file'),
('file.hdr file.img', 'file file.img file.hdr', 'prefix', 'file'),
('file.hdr file.img', 'file file', 'primary', 'file.hdr'),
('file.hdr file.img', 'file file.img', 'primary', 'file.hdr'),
('file.hdr file.img', 'file file.img file.hdr', 'primary', 'file.hdr'),
('file.hdr file.img', 'file file', 'all', 'file.hdr file.img'),
('file.hdr file.img', 'file file.img', 'all', 'file.hdr file.img'),
('file.hdr file.img', 'file file.img file.hdr', 'all', 'file.hdr file.img'),
# multiple files same prefix
('file.hdr file.img file.nii', 'file', 'prefix', 'file'),
('file.hdr file.img file.nii', 'file', 'primary', 'file.hdr file.nii'),
('file.hdr file.img file.nii', 'file', 'all', 'file.hdr file.img file.nii'),
# multiple files
('file1.hdr file1.img file2.nii', 'file1', 'prefix', 'file1'),
('file1.hdr file1.img file2.nii', 'file1', 'primary', 'file1.hdr'),
('file1.hdr file1.img file2.nii', 'file1', 'all', 'file1.hdr file1.img'),
('file1.hdr file1.img file2.nii', 'file1 file2', 'prefix', 'file1 file2'),
('file1.hdr file1.img file2.nii', 'file1 file2', 'primary', 'file1.hdr file2.nii'),
('file1.hdr file1.img file2.nii', 'file1 file2', 'all', 'file1.hdr file1.img file2.nii'),
# no file
('file.nii', 'bag', 'prefix', ''),
('file.nii', 'bag', 'primary', ''),
('file.nii', 'bag', 'all', ''),
# incomplete prefix
('file.nii', 'fi', 'prefix', ''),
('file.nii', 'fi', 'primary', ''),
('file.nii', 'fi', 'all', ''),
]
for to_create, paths, output, expected in tests:
with testdir(to_create.split()) as td:
paths = paths.split()
expected = expected.split()
result = imglob.imglob(paths, output)
assert sorted(result) == sorted(expected)
def test_imglob_shouldFail():
with pytest.raises(ValueError):
imglob.imglob([], 'bag')
#!/usr/bin/env python
#
# test_fsl_abspath.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import os.path as op
import fsl.scripts.fsl_abspath as fsl_abspath
from tests import tempdir, CaptureStdout
def test_usage():
assert fsl_abspath.main([]) != 0
def test_fsl_abspath():
# fsl_abspath just calls os.path.realpath
with tempdir() as td:
oneup = op.dirname(td)
# (input, expected)
tests = [
('file', f'{td}/file'),
('./file', f'{td}/file'),
('../file', f'{oneup}/file'),
('/file', '/file'),
('/one/two/file', '/one/two/file'),
]
for input, expected in tests:
cap = CaptureStdout()
with cap:
ret = fsl_abspath.main([input])
assert ret == 0
assert cap.stdout.strip() == expected
#!/usr/bin/env python
import mock
from unittest import mock
import pytest
import fsl.scripts.imglob as imglob
......@@ -8,7 +11,7 @@ from .. import testdir
from .. import CaptureStdout
def test_imglob_script_shouldPass():
def test_imglob_shouldPass1():
# (files to create, args, expected)
tests = [
......@@ -50,8 +53,81 @@ def test_imglob_script_shouldPass():
assert capture.stdout.strip().split() == expected.split()
def test_imglob_shouldPass2():
# (files to create, paths, output, expected)
tests = [
# normal usage, one file
('file.hdr file.img', 'file', None, 'file'),
('file.hdr file.img', 'file', 'prefix', 'file'),
('file.hdr file.img', 'file', 'primary', 'file.hdr'),
('file.hdr file.img', 'file', 'all', 'file.hdr file.img'),
# incomplete file pair
('file.hdr', 'file', 'prefix', 'file'),
('file.hdr', 'file.hdr', 'prefix', 'file'),
('file.hdr', 'file.img', 'prefix', 'file'),
('file.hdr', 'file', 'primary', 'file.hdr'),
('file.hdr', 'file.hdr', 'primary', 'file.hdr'),
('file.hdr', 'file.img', 'primary', 'file.hdr'),
('file.hdr', 'file', 'all', 'file.hdr'),
('file.hdr', 'file.hdr', 'all', 'file.hdr'),
('file.hdr', 'file.img', 'all', 'file.hdr'),
# same file specified multiple times
('file.hdr file.img', 'file file', 'prefix', 'file'),
('file.hdr file.img', 'file file.img', 'prefix', 'file'),
('file.hdr file.img', 'file file.img file.hdr', 'prefix', 'file'),
('file.hdr file.img', 'file file', 'primary', 'file.hdr'),
('file.hdr file.img', 'file file.img', 'primary', 'file.hdr'),
('file.hdr file.img', 'file file.img file.hdr', 'primary', 'file.hdr'),
('file.hdr file.img', 'file file', 'all', 'file.hdr file.img'),
('file.hdr file.img', 'file file.img', 'all', 'file.hdr file.img'),
('file.hdr file.img', 'file file.img file.hdr', 'all', 'file.hdr file.img'),
# multiple files same prefix
('file.hdr file.img file.nii', 'file', 'prefix', 'file'),
('file.hdr file.img file.nii', 'file', 'primary', 'file.hdr file.nii'),
('file.hdr file.img file.nii', 'file', 'all', 'file.hdr file.img file.nii'),
# multiple files
('file1.hdr file1.img file2.nii', 'file1', 'prefix', 'file1'),
('file1.hdr file1.img file2.nii', 'file1', 'primary', 'file1.hdr'),
('file1.hdr file1.img file2.nii', 'file1', 'all', 'file1.hdr file1.img'),
('file1.hdr file1.img file2.nii', 'file1 file2', 'prefix', 'file1 file2'),
('file1.hdr file1.img file2.nii', 'file1 file2', 'primary', 'file1.hdr file2.nii'),
('file1.hdr file1.img file2.nii', 'file1 file2', 'all', 'file1.hdr file1.img file2.nii'),
# no file
('file.nii', 'bag', 'prefix', ''),
('file.nii', 'bag', 'primary', ''),
('file.nii', 'bag', 'all', ''),
# incomplete prefix
('file.nii', 'fi', 'prefix', ''),
('file.nii', 'fi', 'primary', ''),
('file.nii', 'fi', 'all', ''),
]
for to_create, paths, output, expected in tests:
with testdir(to_create.split()) as td:
paths = paths.split()
expected = expected.split()
result = imglob.imglob(paths, output)
assert sorted(result) == sorted(expected)
def test_imglob_script_shouldFail():
with pytest.raises(ValueError):
imglob.imglob([], 'bag')
capture = CaptureStdout()
with capture:
......
#!/usr/bin/env python
#
# test_imln.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import os
import os.path as op
from unittest import mock
import pytest
from fsl.utils.tempdir import tempdir
import fsl.utils.path as fslpath
import fsl.scripts.imln as imln
from tests import touch
def test_usage():
assert imln.main([]) != 0
with mock.patch('sys.argv', []):
assert imln.main() != 0
def test_imln():
# (files, command, expected links)
tests = [
('a.nii', 'a.nii link.nii', 'link.nii'),
('a.nii', 'a link', 'link.nii'),
('a.nii', 'a.nii link', 'link.nii'),
('a.nii', 'a link.nii', 'link.nii'),
('a.nii', 'a link.nii.gz', 'link.nii'),
('a.nii.gz', 'a.nii.gz link.nii.gz', 'link.nii.gz'),
('a.nii.gz', 'a link', 'link.nii.gz'),
('a.nii.gz', 'a.nii.gz link', 'link.nii.gz'),
('a.nii.gz', 'a link.nii.gz', 'link.nii.gz'),
('a.nii.gz', 'a link.nii', 'link.nii.gz'),
('a.img a.hdr', 'a link', 'link.img link.hdr'),
('a.img a.hdr', 'a link.img', 'link.img link.hdr'),
('a.img a.hdr', 'a link.hdr', 'link.img link.hdr'),
('a.img a.hdr', 'a.img link', 'link.img link.hdr'),
('a.img a.hdr', 'a.hdr link', 'link.img link.hdr'),
('a.img a.hdr', 'a.img link.img', 'link.img link.hdr'),
('a.img a.hdr', 'a.hdr link.hdr', 'link.img link.hdr'),
('a.img a.hdr', 'a.img link.hdr', 'link.img link.hdr'),
('a.img a.hdr', 'a.hdr link.img', 'link.img link.hdr'),
]
for files, command, explinks in tests:
with tempdir():
files = files.split()
command = command.split()
explinks = explinks.split()
for f in files:
touch(f)
assert imln.main(command) == 0
assert sorted(os.listdir('.')) == sorted(files + explinks)
for f, l in zip(sorted(files), sorted(explinks)):
assert op.islink(l)
assert op.isfile(f) and not op.islink(f)
assert op.realpath(l) == op.abspath(f)
# subdirs - imln currently only
# works with absolute paths (we
# make all paths absolute below)
tests = [
('dir/a.nii', 'dir/a dir/link', 'dir/link.nii'),
('dir/a.img dir/a.hdr', 'dir/a dir/link', 'dir/link.img dir/link.hdr'),
('dir/a.nii', 'dir/a link', 'link.nii'),
('dir/a.img dir/a.hdr', 'dir/a link', 'link.img link.hdr'),
('a.nii', 'a dir/link', 'dir/link.nii'),
('a.img a.hdr', 'a dir/link', 'dir/link.img dir/link.hdr'),
]
for files, command, explinks in tests:
with tempdir():
files = files.split()
command = [op.abspath(c) for c in command.split()]
explinks = explinks.split()
os.mkdir('dir')
for f in files:
touch(f)
assert imln.main(command) == 0
for f, l in zip(sorted(files), sorted(explinks)):
assert op.islink(l)
assert op.isfile(f) and not op.islink(f)
assert op.realpath(l) == op.abspath(f)
# error cases
# (files, commnad)
tests = [
('a.img', 'a link'),
('a.nii a.img a.hdr', 'a link'),
]
for files, command in tests:
with tempdir():
files = files.split()
command = command.split()
for f in files:
touch(f)
assert imln.main(command) != 0
assert sorted(os.listdir('.')) == sorted(files)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment