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

Merge branch 'rf/windows_compat' into 'master'

Rf/windows compat

See merge request fsl/fslpy!62
parents dc965dc8 f2ddb58f
No related branches found
No related tags found
No related merge requests found
Showing
with 246 additions and 133 deletions
...@@ -2,6 +2,23 @@ This document contains the ``fslpy`` release history in reverse chronological ...@@ -2,6 +2,23 @@ This document contains the ``fslpy`` release history in reverse chronological
order. order.
1.10.1 (Friday August 3rd 2018)
-------------------------------
Changed
^^^^^^^
* Minor adjustmenets to improve Windows compatibility.
Fixed
^^^^^
* The .mod:`.FEATImage.getCOPE` method was returning PE images.
1.10.0 (Wednesday July 18th 2018) 1.10.0 (Wednesday July 18th 2018)
--------------------------------- ---------------------------------
......
...@@ -357,6 +357,9 @@ def loadClusterResults(featdir, settings, contrast): ...@@ -357,6 +357,9 @@ def loadClusterResults(featdir, settings, contrast):
clusterFile = op.join( clusterFile = op.join(
featdir, 'cluster_zstat{}_std.txt'.format(contrast + 1)) featdir, 'cluster_zstat{}_std.txt'.format(contrast + 1))
if not op.exists(clusterFile):
return None
# In higher levle analysis run in some standard # In higher levle analysis run in some standard
# space, the cluster coordinates are in standard # space, the cluster coordinates are in standard
# space. We transform them to voxel coordinates. # space. We transform them to voxel coordinates.
...@@ -365,9 +368,6 @@ def loadClusterResults(featdir, settings, contrast): ...@@ -365,9 +368,6 @@ def loadClusterResults(featdir, settings, contrast):
getDataFile(featdir), getDataFile(featdir),
loadData=False).worldToVoxMat loadData=False).worldToVoxMat
if not op.exists(clusterFile):
return None
log.debug('Loading cluster results for contrast {} from {}'.format( log.debug('Loading cluster results for contrast {} from {}'.format(
contrast, clusterFile)) contrast, clusterFile))
...@@ -427,48 +427,49 @@ def loadClusterResults(featdir, settings, contrast): ...@@ -427,48 +427,49 @@ def loadClusterResults(featdir, settings, contrast):
# whitespace, and discarding # whitespace, and discarding
# empty lines # empty lines
lines = f.readlines() lines = f.readlines()
lines = [l.strip() for l in lines]
lines = [l for l in lines if l != ''] lines = [line.strip() for line in lines]
lines = [line for line in lines if line != '']
# the first line should contain column
# names, and each other line should # the first line should contain column
# contain the data for one cluster # names, and each other line should
colNames = lines[0] # contain the data for one cluster
clusterLines = lines[1:] colNames = lines[0]
clusterLines = lines[1:]
# each line should be tab-separated
colNames = colNames.split('\t') # each line should be tab-separated
clusterLines = [cl .split('\t') for cl in clusterLines] colNames = colNames.split('\t')
clusterLines = [cl .split('\t') for cl in clusterLines]
# Turn each cluster line into a
# Cluster instance. An error will # Turn each cluster line into a
# be raised if the columm names # Cluster instance. An error will
# are unrecognised (i.e. not in # be raised if the columm names
# the colmap above), or if the # are unrecognised (i.e. not in
# file is poorly formed. # the colmap above), or if the
clusters = [Cluster(**dict(zip(colNames, cl))) for cl in clusterLines] # file is poorly formed.
clusters = [Cluster(**dict(zip(colNames, cl))) for cl in clusterLines]
# Make sure all coordinates are in voxels -
# for first level analyses, the coordXform # Make sure all coordinates are in voxels -
# will be an identity transform (the coords # for first level analyses, the coordXform
# are already in voxels). But for higher # will be an identity transform (the coords
# level, the coords are in mm, and need to # are already in voxels). But for higher
# be transformed to voxels. # level, the coords are in mm, and need to
for c in clusters: # be transformed to voxels.
for c in clusters:
zmax = [c.zmaxx, c.zmaxy, c.zmaxz]
zcog = [c.zcogx, c.zcogy, c.zcogz] zmax = [c.zmaxx, c.zmaxy, c.zmaxz]
copemax = [c.copemaxx, c.copemaxy, c.copemaxz] zcog = [c.zcogx, c.zcogy, c.zcogz]
copemax = [c.copemaxx, c.copemaxy, c.copemaxz]
zmax = transform.transform([zmax], coordXform)[0].round()
zcog = transform.transform([zcog], coordXform)[0].round() zmax = transform.transform([zmax], coordXform)[0].round()
copemax = transform.transform([copemax], coordXform)[0].round() zcog = transform.transform([zcog], coordXform)[0].round()
copemax = transform.transform([copemax], coordXform)[0].round()
c.zmaxx, c.zmaxy, c.zmaxz = zmax
c.zcogx, c.zcogy, c.zcogz = zcog c.zmaxx, c.zmaxy, c.zmaxz = zmax
c.copemax, c.copemaxy, c.copemaxz = copemax c.zcogx, c.zcogy, c.zcogz = zcog
c.copemax, c.copemaxy, c.copemaxz = copemax
return clusters
return clusters
def getDataFile(featdir): def getDataFile(featdir):
......
...@@ -169,30 +169,15 @@ class FEATFSFDesign(object): ...@@ -169,30 +169,15 @@ class FEATFSFDesign(object):
if level == 1: getEVs = getFirstLevelEVs if level == 1: getEVs = getFirstLevelEVs
else: getEVs = getHigherLevelEVs else: getEVs = getHigherLevelEVs
self.__settings = collections.OrderedDict(settings.items()) self.__loadVoxEVs = loadVoxelwiseEVs
self.__design = np.array(designMatrix) self.__settings = collections.OrderedDict(settings.items())
self.__numEVs = self.__design.shape[1] self.__design = np.array(designMatrix)
self.__evs = getEVs(featDir, self.__settings, self.__design) self.__numEVs = self.__design.shape[1]
self.__evs = getEVs(featDir, self.__settings, self.__design)
if len(self.__evs) != self.__numEVs: if len(self.__evs) != self.__numEVs:
raise FSFError('Number of EVs does not match design.mat') raise FSFError('Number of EVs does not match design.mat')
# Load the voxelwise images now,
# so they're ready to be used by
# the getDesign method.
for ev in self.__evs:
if not isinstance(ev, (VoxelwiseEV, VoxelwiseConfoundEV)):
continue
ev.image = None
# The path to some voxelwise
# EVs may not be present -
# see the VoxelwisEV class.
if loadVoxelwiseEVs and (ev.filename is not None):
ev.image = fslimage.Image(ev.filename)
def getEVs(self): def getEVs(self):
"""Returns a list containing the :class:`EV` instances that represent """Returns a list containing the :class:`EV` instances that represent
...@@ -224,7 +209,7 @@ class FEATFSFDesign(object): ...@@ -224,7 +209,7 @@ class FEATFSFDesign(object):
if not isinstance(ev, (VoxelwiseEV, VoxelwiseConfoundEV)): if not isinstance(ev, (VoxelwiseEV, VoxelwiseConfoundEV)):
continue continue
if ev.image is None: if (not self.__loadVoxEVs) or (ev.filename is None):
log.warning('Voxel EV image missing ' log.warning('Voxel EV image missing '
'for ev {}'.format(ev.index)) 'for ev {}'.format(ev.index))
continue continue
...@@ -300,14 +285,15 @@ class VoxelwiseEV(NormalEV): ...@@ -300,14 +285,15 @@ class VoxelwiseEV(NormalEV):
============ ====================================================== ============ ======================================================
``filename`` Path to the image file containing the data for this EV ``filename`` Path to the image file containing the data for this EV
``image`` Reference to the :class:`.Image` object
============ ====================================================== ============ ======================================================
.. note:: The file for voxelwise EVs in a higher level analysis are not .. note:: The file for voxelwise EVs in a higher level analysis are not
copied into the FEAT directory, so if the user has removed them, copied into the FEAT directory, so if the user has removed them,
or moved the .gfeat directory, the file path here will not be or moved the .gfeat directory, the file path here will not be
valid. Therefore, a ``VoxelwiseEV`` will test to see if the valid. Therefore, a ``VoxelwiseEV`` will test to see if the
file exists, and will set the ``filename`` attribute to ``None`` file exists, and will set the ``filename`` and ``image``
it it does not exist. attributes to ``None`` it it does not exist.
""" """
def __init__(self, realIdx, origIdx, title, filename): def __init__(self, realIdx, origIdx, title, filename):
...@@ -330,6 +316,27 @@ class VoxelwiseEV(NormalEV): ...@@ -330,6 +316,27 @@ class VoxelwiseEV(NormalEV):
'exist: {}'.format(filename)) 'exist: {}'.format(filename))
self.filename = None self.filename = None
self.__image = None
def __del__(self):
"""Clears any reference to the voxelwise EV image. """
self.__image = None
@property
def image(self):
"""Returns the :class:`.Image` containing the voxelwise EV data. """
if self.filename is None:
return None
if self.__image is not None:
return self.__image
self.__image = fslimage.Image(self.filename, mmap=False)
return self.__image
class ConfoundEV(EV): class ConfoundEV(EV):
"""Class representing a confound EV. """Class representing a confound EV.
......
...@@ -95,6 +95,16 @@ class FEATImage(fslimage.Image): ...@@ -95,6 +95,16 @@ class FEATImage(fslimage.Image):
self.name = '{}: {}'.format(self.__analysisName, self.name) self.name = '{}: {}'.format(self.__analysisName, self.name)
def __del__(self):
"""Clears references to any loaded images."""
self.__design = None
self.__residuals = None
self.__pes = None
self.__copes = None
self.__zstats = None
self.__clustMasks = None
def getFEATDir(self): def getFEATDir(self):
"""Returns the FEAT directory this image is contained in.""" """Returns the FEAT directory this image is contained in."""
return self.__featDir return self.__featDir
...@@ -245,14 +255,13 @@ class FEATImage(fslimage.Image): ...@@ -245,14 +255,13 @@ class FEATImage(fslimage.Image):
"""Returns the COPE image for the given contrast (0-indexed). """ """Returns the COPE image for the given contrast (0-indexed). """
if self.__copes[con] is None: if self.__copes[con] is None:
copefile = featanalysis.getPEFile(self.__featDir, con) copefile = featanalysis.getCOPEFile(self.__featDir, con)
self.__copes[con] = fslimage.Image( self.__copes[con] = fslimage.Image(
copefile, copefile,
name='{}: COPE{} ({})'.format( name='{}: COPE{} ({})'.format(
self.__analysisName, self.__analysisName,
con + 1, con + 1,
self.contrastNames()[con])) self.contrastNames()[con]))
return self.__copes[con] return self.__copes[con]
......
...@@ -986,11 +986,13 @@ class Image(Nifti): ...@@ -986,11 +986,13 @@ class Image(Nifti):
def __del__(self): def __del__(self):
"""Closes any open file handles, and clears some references. """ """Closes any open file handles, and clears some references. """
self.header = None
self.__nibImage = None self.__nibImage = None
self.__imageWrapper = None self.__imageWrapper = None
if getattr(self, '__fileobj', None) is not None: if getattr(self, '__fileobj', None) is not None:
self.__fileobj.close() self.__fileobj.close()
self.__fileobj = None
def getImageWrapper(self): def getImageWrapper(self):
......
...@@ -137,6 +137,7 @@ def imcp(src, ...@@ -137,6 +137,7 @@ def imcp(src,
img = nib.load(src) img = nib.load(src)
nib.save(img, dest) nib.save(img, dest)
img = None
if move: if move:
# if input is an image pair, we # if input is an image pair, we
......
...@@ -65,7 +65,7 @@ def shallowest(path, suffixes): ...@@ -65,7 +65,7 @@ def shallowest(path, suffixes):
path = path.strip() path = path.strip()
# We've reached the root of the file system # We've reached the root of the file system
if path == op.sep or path == '': if path == op.sep or path == '' or op.splitdrive(path)[1] == '':
return None return None
path = path.rstrip(op.sep) path = path.rstrip(op.sep)
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
# #
"""This module provides some functions for running shell commands. """This module provides some functions for running shell commands.
.. note:: The functions in this module are only known to work in Unix-like
environments.
.. autosummary:: .. autosummary::
:nosignatures: :nosignatures:
......
...@@ -91,7 +91,6 @@ import os ...@@ -91,7 +91,6 @@ import os
import re import re
import sys import sys
import glob import glob
import shutil
import random import random
import string import string
import fnmatch import fnmatch
...@@ -864,6 +863,7 @@ class _FileOrThing(object): ...@@ -864,6 +863,7 @@ class _FileOrThing(object):
fval = self.__load(fullpath) fval = self.__load(fullpath)
if fval is not None: if fval is not None:
prefixed = self.__removeExt(prefixed) prefixed = self.__removeExt(prefixed)
prefPat = prefPat.replace('\\', '\\\\')
prefixed = re.sub('^' + prefPat, prefName, prefixed) prefixed = re.sub('^' + prefPat, prefName, prefixed)
result[prefixed] = fval result[prefixed] = fval
break break
...@@ -915,7 +915,7 @@ def fileOrImage(*args, **kwargs): ...@@ -915,7 +915,7 @@ def fileOrImage(*args, **kwargs):
# create an independent in-memory # create an independent in-memory
# copy of the image file # copy of the image file
img = nib.load(path) img = nib.load(path, mmap=False)
# if any arguments were fsl images, # if any arguments were fsl images,
# that takes precedence. # that takes precedence.
......
...@@ -294,7 +294,8 @@ def make_mock_feat_analysis(featdir, ...@@ -294,7 +294,8 @@ def make_mock_feat_analysis(featdir,
if indata: if indata:
filtfunc = op.join(featdir, 'filtered_func_data.nii.gz') filtfunc = op.join(featdir, 'filtered_func_data.nii.gz')
make_random_image(filtfunc, shape4D, xform) img = make_random_image(filtfunc, shape4D, xform)
del img
# and some dummy voxelwise EV files # and some dummy voxelwise EV files
if voxEVs: if voxEVs:
...@@ -311,7 +312,10 @@ def make_mock_feat_analysis(featdir, ...@@ -311,7 +312,10 @@ def make_mock_feat_analysis(featdir,
data = data.reshape(list(shape) + [1]).repeat(timepoints, axis=3) data = data.reshape(list(shape) + [1]).repeat(timepoints, axis=3)
data[..., :] += range(i, i + timepoints) data[..., :] += range(i, i + timepoints)
nib.save(nib.nifti1.Nifti1Image(data, xform), vf) img = nib.nifti1.Nifti1Image(data, xform)
nib.save(img, vf)
del img
otherFiles = [] otherFiles = []
otherShapes = [] otherShapes = []
...@@ -342,7 +346,8 @@ def make_mock_feat_analysis(featdir, ...@@ -342,7 +346,8 @@ def make_mock_feat_analysis(featdir,
otherShapes.extend([shape] * len(files)) otherShapes.extend([shape] * len(files))
for f, s in zip(otherFiles, otherShapes): for f, s in zip(otherFiles, otherShapes):
make_random_image(f, s, xform) img = make_random_image(f, s, xform)
del img
return featdir return featdir
......
...@@ -41,7 +41,7 @@ def seed(request): ...@@ -41,7 +41,7 @@ def seed(request):
seed = request.config.getoption('--seed') seed = request.config.getoption('--seed')
if seed is None: if seed is None:
seed = np.random.randint(2 ** 32) seed = np.random.randint(2 ** 30)
np.random.seed(seed) np.random.seed(seed)
random .seed(seed) random .seed(seed)
......
...@@ -21,19 +21,19 @@ def test_getDTIFitDataPrefix_and_isDTIFitPath(): ...@@ -21,19 +21,19 @@ def test_getDTIFitDataPrefix_and_isDTIFitPath():
for s in suffixes: for s in suffixes:
path = op.join(dir, '{}{}'.format(prefix, s)) path = op.join(dir, '{}{}'.format(prefix, s))
with open(path, 'wt') as f: with open(path, 'wt') as f:
f.write(path) f.write(path)
prefixes = ['dti', 'blob', 'random-prefix', '01234'] prefixes = ['dti', 'blob', 'random-prefix', '01234']
suffixes = ['_V1.nii', '_V2.nii', '_V3.nii', suffixes = ['_V1.nii', '_V2.nii', '_V3.nii',
'_L1.nii', '_L2.nii', '_L3.nii'] '_L1.nii', '_L2.nii', '_L3.nii']
badSuffixes = ['_V1.txt', '_V2.nii', '_V3.nii', badSuffixes = ['_V1.txt', '_V2.nii', '_V3.nii',
'_L1.txt', '_L2.tar', '_L3.nii'] '_L1.txt', '_L2.tar', '_L3.nii']
# Valid dtifit directories # Valid dtifit directories
with tests.testdir() as testdir: with tests.testdir() as testdir:
for p in prefixes: for p in prefixes:
tests.cleardir(testdir) tests.cleardir(testdir)
make_dtifit_dir(testdir, p, suffixes) make_dtifit_dir(testdir, p, suffixes)
assert dtifit.getDTIFitDataPrefix(testdir) == p assert dtifit.getDTIFitDataPrefix(testdir) == p
...@@ -82,6 +82,7 @@ def test_looksLikeTensorImage(): ...@@ -82,6 +82,7 @@ def test_looksLikeTensorImage():
img = fslimage.Image(fname) img = fslimage.Image(fname)
assert dtifit.looksLikeTensorImage(img) == expected assert dtifit.looksLikeTensorImage(img) == expected
img = None
def test_decomposeTensorMatrix(): def test_decomposeTensorMatrix():
...@@ -102,7 +103,7 @@ def test_decomposeTensorMatrix(): ...@@ -102,7 +103,7 @@ def test_decomposeTensorMatrix():
[[ 0.701921939849854, -0.711941838264465, 0.021080270409584], [[ 0.701921939849854, -0.711941838264465, 0.021080270409584],
[-0.700381875038147, -0.695301055908203, -0.16131255030632 ], [-0.700381875038147, -0.695301055908203, -0.16131255030632 ],
[-0.129502296447754, -0.098464585840702, 0.986678183078766]], [-0.129502296447754, -0.098464585840702, 0.986678183078766]],
[[-0.993700802326202, -0.104962401092052, -0.039262764155865], [[-0.993700802326202, -0.104962401092052, -0.039262764155865],
[-0.081384353339672, 0.916762292385101, -0.391054302453995], [-0.081384353339672, 0.916762292385101, -0.391054302453995],
[-0.077040620148182, 0.385395616292953, 0.919529736042023]], [-0.077040620148182, 0.385395616292953, 0.919529736042023]],
[[ 0.068294189870358, -0.666985750198364, 0.741933941841125], [[ 0.068294189870358, -0.666985750198364, 0.741933941841125],
...@@ -112,7 +113,7 @@ def test_decomposeTensorMatrix(): ...@@ -112,7 +113,7 @@ def test_decomposeTensorMatrix():
tensorMatrices = tensorMatrices.reshape(1, 1, 3, 6) tensorMatrices = tensorMatrices.reshape(1, 1, 3, 6)
expEigVals = expEigVals .reshape(1, 1, 3, 3) expEigVals = expEigVals .reshape(1, 1, 3, 3)
expEigVecs = expEigVecs .reshape(1, 1, 3, 3, 3) expEigVecs = expEigVecs .reshape(1, 1, 3, 3, 3)
v1, v2, v3, l1, l2, l3 = dtifit.decomposeTensorMatrix(tensorMatrices) v1, v2, v3, l1, l2, l3 = dtifit.decomposeTensorMatrix(tensorMatrices)
expV1 = expEigVecs[:, :, :, 0] expV1 = expEigVecs[:, :, :, 0]
...@@ -129,7 +130,7 @@ def test_decomposeTensorMatrix(): ...@@ -129,7 +130,7 @@ def test_decomposeTensorMatrix():
# Vector signs are arbitrary # Vector signs are arbitrary
for vox in range(3): for vox in range(3):
for resvec, expvec in zip([v1, v2, v3], [expV1, expV2, expV3]): for resvec, expvec in zip([v1, v2, v3], [expV1, expV2, expV3]):
resvec = resvec[:, :, vox] resvec = resvec[:, :, vox]
expvec = expvec[:, :, vox] expvec = expvec[:, :, vox]
...@@ -172,3 +173,7 @@ def test_DTIFitTensor(): ...@@ -172,3 +173,7 @@ def test_DTIFitTensor():
assert np.all(np.isclose(dtiobj.voxToWorldMat, v1.voxToWorldMat)) assert np.all(np.isclose(dtiobj.voxToWorldMat, v1.voxToWorldMat))
assert np.all(np.isclose(dtiobj.shape[:3], v1.shape[:3])) assert np.all(np.isclose(dtiobj.shape[:3], v1.shape[:3]))
assert np.all(np.isclose(dtiobj.pixdim[:3], v1.pixdim[:3])) assert np.all(np.isclose(dtiobj.pixdim[:3], v1.pixdim[:3]))
del v1
del dtiobj
v1 = None
...@@ -28,3 +28,7 @@ def test_ensureIsImage(): ...@@ -28,3 +28,7 @@ def test_ensureIsImage():
for l in loaded: for l in loaded:
assert isinstance(l, nib.nifti1.Nifti1Image) assert isinstance(l, nib.nifti1.Nifti1Image)
assert np.all(img.get_data() == l.get_data()) assert np.all(img.get_data() == l.get_data())
l = None
loaded = None
img = None
...@@ -103,17 +103,12 @@ with the following commands: ...@@ -103,17 +103,12 @@ with the following commands:
""" """
import os import os.path as op
import os.path as op import numpy as np
import itertools as it
import glob
import shutil
import numpy as np
import pytest import pytest
import tests import tests
import fsl.data.image as fslimage
import fsl.data.featdesign as featdesign import fsl.data.featdesign as featdesign
import fsl.data.featanalysis as featanalysis import fsl.data.featanalysis as featanalysis
...@@ -172,6 +167,9 @@ def test_FEATFSFDesign(): ...@@ -172,6 +167,9 @@ def test_FEATFSFDesign():
assert des.getDesign().shape == desshape assert des.getDesign().shape == desshape
assert des.getDesign(rvox).shape == desshape assert des.getDesign(rvox).shape == desshape
del des
des = None
def test_FEATFSFDesign_firstLevelVoxelwiseEV(seed): def test_FEATFSFDesign_firstLevelVoxelwiseEV(seed):
...@@ -214,6 +212,8 @@ def test_FEATFSFDesign_firstLevelVoxelwiseEV(seed): ...@@ -214,6 +212,8 @@ def test_FEATFSFDesign_firstLevelVoxelwiseEV(seed):
for i, evidx in enumerate(voxevIdxs): for i, evidx in enumerate(voxevIdxs):
expect = np.arange(i, i + 45) + offset expect = np.arange(i, i + 45) + offset
assert np.all(np.isclose(matrix[:, evidx], expect)) assert np.all(np.isclose(matrix[:, evidx], expect))
del design
design = None
def test_getFirstLevelEVs_1(): def test_getFirstLevelEVs_1():
...@@ -240,6 +240,8 @@ def test_getFirstLevelEVs_1(): ...@@ -240,6 +240,8 @@ def test_getFirstLevelEVs_1():
assert isinstance(evs[i], evtype) assert isinstance(evs[i], evtype)
for k, v in atts.items(): for k, v in atts.items():
assert getattr(evs[i], k) == v assert getattr(evs[i], k) == v
del evs
evs = None
def test_getFirstLevelEVs_2(): def test_getFirstLevelEVs_2():
...@@ -267,6 +269,8 @@ def test_getFirstLevelEVs_2(): ...@@ -267,6 +269,8 @@ def test_getFirstLevelEVs_2():
assert isinstance(evs[i], evtype) assert isinstance(evs[i], evtype)
for k, v in atts.items(): for k, v in atts.items():
assert getattr(evs[i], k) == v assert getattr(evs[i], k) == v
del evs
evs = None
def test_getFirstLevelEVs_3(): def test_getFirstLevelEVs_3():
...@@ -307,7 +311,6 @@ def test_getFirstLevelEVs_3(): ...@@ -307,7 +311,6 @@ def test_getFirstLevelEVs_3():
(featdesign.ConfoundEV, {'index' : 30, 'confIndex' : 0}), (featdesign.ConfoundEV, {'index' : 30, 'confIndex' : 0}),
(featdesign.ConfoundEV, {'index' : 31, 'confIndex' : 1})] (featdesign.ConfoundEV, {'index' : 31, 'confIndex' : 1})]
evs = featdesign.getFirstLevelEVs(featdir, settings, matrix) evs = featdesign.getFirstLevelEVs(featdir, settings, matrix)
assert len(evs) == 32 assert len(evs) == 32
...@@ -318,6 +321,10 @@ def test_getFirstLevelEVs_3(): ...@@ -318,6 +321,10 @@ def test_getFirstLevelEVs_3():
for k, v in atts.items(): for k, v in atts.items():
assert getattr(evs[i], k) == v assert getattr(evs[i], k) == v
del evs
evs = None
def test_getFirstLevelEVs_realdata(): def test_getFirstLevelEVs_realdata():
featdir = op.join(datadir, '1stlevel_realdata.feat') featdir = op.join(datadir, '1stlevel_realdata.feat')
settings = featanalysis.loadSettings(featdir) settings = featanalysis.loadSettings(featdir)
...@@ -336,7 +343,8 @@ def test_getFirstLevelEVs_realdata(): ...@@ -336,7 +343,8 @@ def test_getFirstLevelEVs_realdata():
assert isinstance(evs[i], evtype) assert isinstance(evs[i], evtype)
for k, v in atts.items(): for k, v in atts.items():
assert getattr(evs[i], k) == v assert getattr(evs[i], k) == v
del evs
evs = None
def test_getHigherLevelEVs_1(): def test_getHigherLevelEVs_1():
...@@ -351,8 +359,8 @@ def test_getHigherLevelEVs_1(): ...@@ -351,8 +359,8 @@ def test_getHigherLevelEVs_1():
assert isinstance(evs[0], featdesign.NormalEV) assert isinstance(evs[0], featdesign.NormalEV)
assert evs[0].index == 0 assert evs[0].index == 0
assert evs[0].origIndex == 0 assert evs[0].origIndex == 0
del evs
evs = None
def test_getHigherLevelEVs_2(): def test_getHigherLevelEVs_2():
...@@ -368,7 +376,8 @@ def test_getHigherLevelEVs_2(): ...@@ -368,7 +376,8 @@ def test_getHigherLevelEVs_2():
assert evs[0].index == 0 assert evs[0].index == 0
assert evs[0].origIndex == 0 assert evs[0].origIndex == 0
assert isinstance(evs[1], featdesign.VoxelwiseEV) assert isinstance(evs[1], featdesign.VoxelwiseEV)
del evs
evs = None
def test_loadDesignMat(): def test_loadDesignMat():
......
...@@ -29,6 +29,7 @@ featdirs = ['1stlevel_1.feat', '1stlevel_2.feat', '1stlevel_2.feat', ...@@ -29,6 +29,7 @@ featdirs = ['1stlevel_1.feat', '1stlevel_2.feat', '1stlevel_2.feat',
'2ndlevel_2.gfeat/cope1.feat', '2ndlevel_2.gfeat/cope2.feat', '2ndlevel_2.gfeat/cope1.feat', '2ndlevel_2.gfeat/cope2.feat',
'2ndlevel_realdata.gfeat/cope1.feat', '2ndlevel_realdata.gfeat/cope1.feat',
'2ndlevel_realdata.gfeat/cope2.feat'] '2ndlevel_realdata.gfeat/cope2.feat']
featdirs = [op.join(*d.split('/')) for d in featdirs]
shapes = [(64, 64, 5, 45), shapes = [(64, 64, 5, 45),
(64, 64, 5, 45), (64, 64, 5, 45),
(64, 64, 5, 45), (64, 64, 5, 45),
...@@ -90,7 +91,7 @@ def test_FEATImage_attributes(): ...@@ -90,7 +91,7 @@ def test_FEATImage_attributes():
clustMasks=False) clustMasks=False)
else: else:
featdir = op.join(datadir, featdir) featdir = op.join(datadir, featdir)
# Now create a FEATImage. We validate its # Now create a FEATImage. We validate its
# attributes against the values returned by # attributes against the values returned by
# the functions in featdesign/featanalysis. # the functions in featdesign/featanalysis.
...@@ -125,12 +126,16 @@ def test_FEATImage_attributes(): ...@@ -125,12 +126,16 @@ def test_FEATImage_attributes():
expect = featanalysis.loadClusterResults(featdir, settings, ci) expect = featanalysis.loadClusterResults(featdir, settings, ci)
assert len(result) == len(expect) assert len(result) == len(expect)
assert all([rc.nvoxels == ec.nvoxels for rc, ec in zip(result, expect)]) assert all([rc.nvoxels == ec.nvoxels for rc, ec in zip(result, expect)])
del design
del fi
fi = None
def test_FEATImage_imageAccessors(): def test_FEATImage_imageAccessors():
for featdir in TEST_ANALYSES.keys(): for featdir in TEST_ANALYSES.keys():
shape = TEST_ANALYSES[featdir]['shape'] shape = TEST_ANALYSES[featdir]['shape']
xform = TEST_ANALYSES[featdir]['xform'] xform = TEST_ANALYSES[featdir]['xform']
...@@ -152,25 +157,26 @@ def test_FEATImage_imageAccessors(): ...@@ -152,25 +157,26 @@ def test_FEATImage_imageAccessors():
nevs = fi.numEVs() nevs = fi.numEVs()
ncons = fi.numContrasts() ncons = fi.numContrasts()
# Testing the FEATImage intenral cache # Testing the FEATImage internal cache
for i in range(2): for i in range(2):
assert fi.getResiduals().shape == shape4D assert fi.getResiduals().shape == shape4D
for ev in range(nevs): for ev in range(nevs):
assert fi.getPE(ev).shape == shape assert fi.getPE(ev).shape == shape
for con in range(ncons): for con in range(ncons):
assert fi.getCOPE( con).shape == shape assert fi.getCOPE( con).shape == shape
assert fi.getZStats( con).shape == shape assert fi.getZStats( con).shape == shape
assert fi.getClusterMask(con).shape == shape assert fi.getClusterMask(con).shape == shape
del fi
fi = None
def test_FEATImage_nostats(): def test_FEATImage_nostats():
featdir = op.join(datadir, '1stlevel_nostats.feat') featdir = op.join(datadir, '1stlevel_nostats.feat')
shape = (4, 4, 5, 45) shape = (4, 4, 5, 45)
with tests.testdir() as testdir: with tests.testdir() as testdir:
featdir = tests.make_mock_feat_analysis(featdir, testdir, shape) featdir = tests.make_mock_feat_analysis(featdir, testdir, shape)
fi = featimage.FEATImage(featdir) fi = featimage.FEATImage(featdir)
...@@ -181,13 +187,15 @@ def test_FEATImage_nostats(): ...@@ -181,13 +187,15 @@ def test_FEATImage_nostats():
with pytest.raises(Exception): with pytest.raises(Exception):
fi.fit([1, 2, 3], (2, 2, 2)) fi.fit([1, 2, 3], (2, 2, 2))
with pytest.raises(Exception): with pytest.raises(Exception):
fi.partialFit([1, 2, 3], (2, 2, 2)) fi.partialFit([1, 2, 3], (2, 2, 2))
del fi
fi = None
def test_FEATImage_fit_firstLevel(): def test_FEATImage_fit_firstLevel():
featdir = op.join(datadir, '1stlevel_realdata.feat') featdir = op.join(datadir, '1stlevel_realdata.feat')
fi = featimage.FEATImage(featdir) fi = featimage.FEATImage(featdir)
expect = np.array([ expect = np.array([
...@@ -202,8 +210,8 @@ def test_FEATImage_fit_firstLevel(): ...@@ -202,8 +210,8 @@ def test_FEATImage_fit_firstLevel():
10287.91883737, 10325.38456267, 10341.92299781, 10347.17916861, 10287.91883737, 10325.38456267, 10341.92299781, 10347.17916861,
10348.58339616, 10348.89634025, 10348.93522057, 10345.25397481, 10348.58339616, 10348.89634025, 10348.93522057, 10345.25397481,
10288.9236822 , 10315.64160242, 10449.39567496, 10558.66999883, 10288.9236822 , 10315.64160242, 10449.39567496, 10558.66999883,
10597.64918744]) 10597.64918744])
# bad contrast # bad contrast
with pytest.raises(Exception): with pytest.raises(Exception):
fi.fit([1, 2, 3, 4, 5, 6, 7], (2, 2, 2)) fi.fit([1, 2, 3, 4, 5, 6, 7], (2, 2, 2))
...@@ -214,20 +222,24 @@ def test_FEATImage_fit_firstLevel(): ...@@ -214,20 +222,24 @@ def test_FEATImage_fit_firstLevel():
result = fi.fit([1, 1, 1, 1], (2, 2, 2)) result = fi.fit([1, 1, 1, 1], (2, 2, 2))
assert np.all(np.isclose(result, expect)) assert np.all(np.isclose(result, expect))
del fi
fi = None
def test_FEATImage_fit_higherLevel(): def test_FEATImage_fit_higherLevel():
featdir = op.join(datadir, '2ndlevel_realdata.gfeat/cope1.feat') featdir = op.join(datadir, '2ndlevel_realdata.gfeat/cope1.feat')
fi = featimage.FEATImage(featdir) fi = featimage.FEATImage(featdir)
expect = np.array([86.37929535, 86.37929535, 86.37929535]) expect = np.array([86.37929535, 86.37929535, 86.37929535])
result = fi.fit([1], (5, 5, 5)) result = fi.fit([1], (5, 5, 5))
assert np.all(np.isclose(result, expect)) assert np.all(np.isclose(result, expect))
del fi
fi = None
def test_FEATImage_partialFit(): def test_FEATImage_partialFit():
featdir = op.join(datadir, '1stlevel_realdata.feat') featdir = op.join(datadir, '1stlevel_realdata.feat')
fi = featimage.FEATImage(featdir) fi = featimage.FEATImage(featdir)
expect = np.array([ expect = np.array([
...@@ -244,14 +256,16 @@ def test_FEATImage_partialFit(): ...@@ -244,14 +256,16 @@ def test_FEATImage_partialFit():
10203.21032619, 10136.1942605 , 10128.23728873, 10416.78984136, 10203.21032619, 10136.1942605 , 10128.23728873, 10416.78984136,
10118.51262128]) 10118.51262128])
result = fi.partialFit([1, 1, 1, 1], (2, 2, 2)) result = fi.partialFit([1, 1, 1, 1], (2, 2, 2))
assert np.all(np.isclose(result, expect)) assert np.all(np.isclose(result, expect))
del fi
fi = None
def test_modelFit(seed): def test_modelFit(seed):
for i in range(500): for i in range(500):
# 2 evs, 20 timepoints # 2 evs, 20 timepoints
# First EV is a boxcar, # First EV is a boxcar,
# second is a random regressor # second is a random regressor
...@@ -264,12 +278,12 @@ def test_modelFit(seed): ...@@ -264,12 +278,12 @@ def test_modelFit(seed):
design[:, ev] = design[:, ev] - design[:, ev].mean() design[:, ev] = design[:, ev] - design[:, ev].mean()
# Generate some random PEs, and # Generate some random PEs, and
# generate the data that would # generate the data that would
# have resulted in them # have resulted in them
pes = np.random.random(2) pes = np.random.random(2)
expect = np.dot(design, pes) expect = np.dot(design, pes)
contrast = [1] * design.shape[1] contrast = [1] * design.shape[1]
result1 = featimage.modelFit(expect, design, contrast, pes, True) result1 = featimage.modelFit(expect, design, contrast, pes, True)
result2 = featimage.modelFit(expect, design, contrast, pes, False) result2 = featimage.modelFit(expect, design, contrast, pes, False)
......
...@@ -167,10 +167,9 @@ def test_loadVertexData_mgh(): ...@@ -167,10 +167,9 @@ def test_loadVertexData_mgh():
mesh = fslfs.FreesurferMesh('lh.pial') mesh = fslfs.FreesurferMesh('lh.pial')
assert np.all(np.isclose(mesh.loadVertexData('lh.vdata.mgh'), data.reshape(-1, 1))) assert np.all(np.isclose(mesh.loadVertexData('lh.vdata.mgh'), data.reshape(-1, 1)))
del img
del mesh
img = None
def test_loadVertexData_annot(): def test_loadVertexData_annot():
......
...@@ -75,6 +75,10 @@ def test_deepest(): ...@@ -75,6 +75,10 @@ def test_deepest():
] ]
for path, suffixes, output in tests: for path, suffixes, output in tests:
path = op.join(*path.split('/'))
if output is not None:
output = op.join(*output.split('/'))
assert fslpath.deepest(path, suffixes) == output assert fslpath.deepest(path, suffixes) == output
...@@ -107,6 +111,11 @@ def test_shallowest(): ...@@ -107,6 +111,11 @@ def test_shallowest():
] ]
for path, suffixes, output in tests: for path, suffixes, output in tests:
path = op.join(*path.split('/'))
if output is not None:
output = op.join(*output.split('/'))
assert fslpath.shallowest(path, suffixes) == output assert fslpath.shallowest(path, suffixes) == output
...@@ -120,6 +129,8 @@ def test_allFiles(): ...@@ -120,6 +129,8 @@ def test_allFiles():
'a/b/d/1', 'a/b/d/1',
] ]
create = [op.join(*c.split('/')) for c in create]
with testdir(create) as td: with testdir(create) as td:
assert (sorted(fslpath.allFiles('.')) == assert (sorted(fslpath.allFiles('.')) ==
sorted([op.join('.', c) for c in create])) sorted([op.join('.', c) for c in create]))
......
...@@ -622,5 +622,5 @@ def test_mutex(): ...@@ -622,5 +622,5 @@ def test_mutex():
# Either t1 has to start and # Either t1 has to start and
# finish before t2 or vice versa # finish before t2 or vice versa
assert (t[0].method2start > t[0].method1end or assert (t[0].method2start >= t[0].method1end or
t[0].method1start > t[0].method2end) t[0].method1start >= t[0].method2end)
...@@ -314,6 +314,7 @@ def _test_Image_atts(imgtype): ...@@ -314,6 +314,7 @@ def _test_Image_atts(imgtype):
allowedExts=allowedExts, allowedExts=allowedExts,
mustExist=True, mustExist=True,
fileGroups=fileGroups) fileGroups=fileGroups)
i = None
def test_Image_atts2_analyze(): _test_Image_atts2(0) def test_Image_atts2_analyze(): _test_Image_atts2(0)
...@@ -530,7 +531,7 @@ def _test_Image_orientation(imgtype, voxorient): ...@@ -530,7 +531,7 @@ def _test_Image_orientation(imgtype, voxorient):
make_image(imagefile, imgtype, (10, 10, 10), pixdims, np.float32) make_image(imagefile, imgtype, (10, 10, 10), pixdims, np.float32)
image = fslimage.Image(imagefile) image = fslimage.Image(imagefile, mmap=False)
# analyze images are always assumed to be # analyze images are always assumed to be
# stored in radiological (LAS) orientation # stored in radiological (LAS) orientation
...@@ -566,6 +567,7 @@ def _test_Image_orientation(imgtype, voxorient): ...@@ -566,6 +567,7 @@ def _test_Image_orientation(imgtype, voxorient):
assert image.getOrientation(0, affine) == expectvox0Orientation assert image.getOrientation(0, affine) == expectvox0Orientation
assert image.getOrientation(1, affine) == expectvox1Orientation assert image.getOrientation(1, affine) == expectvox1Orientation
assert image.getOrientation(2, affine) == expectvox2Orientation assert image.getOrientation(2, affine) == expectvox2Orientation
image = None
def test_Image_sqforms_nifti1_normal(): _test_Image_sqforms(1, 1, 1) def test_Image_sqforms_nifti1_normal(): _test_Image_sqforms(1, 1, 1)
...@@ -693,6 +695,8 @@ def _test_Image_changeXform(imgtype, sformcode=None, qformcode=None): ...@@ -693,6 +695,8 @@ def _test_Image_changeXform(imgtype, sformcode=None, qformcode=None):
# ANALYZE affine is not editable # ANALYZE affine is not editable
with pytest.raises(Exception): with pytest.raises(Exception):
img.voxToWorldMat = newXform img.voxToWorldMat = newXform
del img
del image
return return
img.voxToWorldMat = newXform img.voxToWorldMat = newXform
...@@ -709,6 +713,9 @@ def _test_Image_changeXform(imgtype, sformcode=None, qformcode=None): ...@@ -709,6 +713,9 @@ def _test_Image_changeXform(imgtype, sformcode=None, qformcode=None):
assert np.all(np.isclose(img.worldToVoxMat, invx)) assert np.all(np.isclose(img.worldToVoxMat, invx))
assert img.getXFormCode('sform') == expSformCode assert img.getXFormCode('sform') == expSformCode
assert img.getXFormCode('qform') == expQformCode assert img.getXFormCode('qform') == expQformCode
del img
del image
image = None
def test_Image_changeData_analyze(seed): _test_Image_changeData(0) def test_Image_changeData_analyze(seed): _test_Image_changeData(0)
...@@ -724,14 +731,15 @@ def _test_Image_changeData(imgtype): ...@@ -724,14 +731,15 @@ def _test_Image_changeData(imgtype):
make_image(imagefile, imgtype) make_image(imagefile, imgtype)
img = fslimage.Image(imagefile) img = fslimage.Image(imagefile, mmap=False)
shape = img.shape
notified = {} notified = {}
def randvox(): def randvox():
return (np.random.randint(0, img.shape[0]), return (np.random.randint(0, shape[0]),
np.random.randint(0, img.shape[1]), np.random.randint(0, shape[1]),
np.random.randint(0, img.shape[2])) np.random.randint(0, shape[2]))
def onData(*a): def onData(*a):
notified['data'] = True notified['data'] = True
...@@ -806,6 +814,10 @@ def _test_Image_changeData(imgtype): ...@@ -806,6 +814,10 @@ def _test_Image_changeData(imgtype):
assert notified.get('dataRange', False) assert notified.get('dataRange', False)
assert np.isclose(img[maxx, maxy, maxz], newdmax) assert np.isclose(img[maxx, maxy, maxz], newdmax)
assert np.all(np.isclose(img.dataRange, (newdmin, newdmax))) assert np.all(np.isclose(img.dataRange, (newdmin, newdmax)))
img.deregister('name1', 'data')
img.deregister('name2', 'data')
img.deregister('name3', 'data')
img = None
def test_Image_2D_analyze(): _test_Image_2D(0) def test_Image_2D_analyze(): _test_Image_2D(0)
...@@ -851,6 +863,7 @@ def _test_Image_2D(imgtype): ...@@ -851,6 +863,7 @@ def _test_Image_2D(imgtype):
assert tuple(map(float, shape)) == tuple(map(float, image .shape)) assert tuple(map(float, shape)) == tuple(map(float, image .shape))
assert tuple(map(float, shape)) == tuple(map(float, image[:].shape)) assert tuple(map(float, shape)) == tuple(map(float, image[:].shape))
assert tuple(map(float, pixdim)) == tuple(map(float, image .pixdim)) assert tuple(map(float, pixdim)) == tuple(map(float, image .pixdim))
image = None
def test_Image_5D_analyze(): _test_Image_5D(0) def test_Image_5D_analyze(): _test_Image_5D(0)
...@@ -880,6 +893,8 @@ def _test_Image_5D(imgtype): ...@@ -880,6 +893,8 @@ def _test_Image_5D(imgtype):
assert img.shape == dims assert img.shape == dims
assert img.ndim == 5 assert img.ndim == 5
assert img.data.shape == dims assert img.data.shape == dims
del img
img = None
def test_Image_voxToScaledVox_analyze(): _test_Image_voxToScaledVox(0) def test_Image_voxToScaledVox_analyze(): _test_Image_voxToScaledVox(0)
...@@ -917,6 +932,7 @@ def _test_Image_voxToScaledVox(imgtype): ...@@ -917,6 +932,7 @@ def _test_Image_voxToScaledVox(imgtype):
assert np.all(np.isclose(expected, img.voxToScaledVoxMat)) assert np.all(np.isclose(expected, img.voxToScaledVoxMat))
assert np.all(np.isclose(invexpected, img.scaledVoxToVoxMat)) assert np.all(np.isclose(invexpected, img.scaledVoxToVoxMat))
img = None
def test_Image_sameSpace(): def test_Image_sameSpace():
...@@ -1022,6 +1038,7 @@ def _test_Image_save(imgtype): ...@@ -1022,6 +1038,7 @@ def _test_Image_save(imgtype):
for (x, y, z), v in zip(randvoxes, randvals): for (x, y, z), v in zip(randvoxes, randvals):
assert np.isclose(img[x, y, z], v) assert np.isclose(img[x, y, z], v)
img2 = None
def test_image_resample(seed): def test_image_resample(seed):
...@@ -1035,7 +1052,7 @@ def test_image_resample(seed): ...@@ -1035,7 +1052,7 @@ def test_image_resample(seed):
shape = np.random.randint(5, 100, 3) shape = np.random.randint(5, 100, 3)
make_random_image(fname, shape) make_random_image(fname, shape)
img = fslimage.Image(fname) img = fslimage.Image(fname, mmap=False)
# resampling to the same shape should be a no-op # resampling to the same shape should be a no-op
samei, samex = img.resample(shape) samei, samex = img.resample(shape)
...@@ -1049,7 +1066,8 @@ def test_image_resample(seed): ...@@ -1049,7 +1066,8 @@ def test_image_resample(seed):
resampled, xf = img.resample(rshape, order=0) resampled, xf = img.resample(rshape, order=0)
img.save('base.nii.gz') img.save('base.nii.gz')
fslimage.Image(resampled, xform=xf).save('res.nii.gz') fslimage.Image(resampled, xform=xf,
mmap=False).save('res.nii.gz')
assert tuple(resampled.shape) == tuple(rshape) assert tuple(resampled.shape) == tuple(rshape)
...@@ -1102,6 +1120,8 @@ def test_image_resample(seed): ...@@ -1102,6 +1120,8 @@ def test_image_resample(seed):
resampled = img.resample((15, 15, 15), slc)[0] resampled = img.resample((15, 15, 15), slc)[0]
assert tuple(resampled.shape) == (15, 15, 15) assert tuple(resampled.shape) == (15, 15, 15)
del img
img = None
def test_Image_init_xform_nifti1(): _test_Image_init_xform(1) def test_Image_init_xform_nifti1(): _test_Image_init_xform(1)
...@@ -1142,7 +1162,6 @@ def _test_Image_init_xform(imgtype): ...@@ -1142,7 +1162,6 @@ def _test_Image_init_xform(imgtype):
assert fsform_code == sform_code assert fsform_code == sform_code
assert fqform_code == qform_code assert fqform_code == qform_code
# an image created off # an image created off
# an xform only should # an xform only should
# get its sform set # get its sform set
...@@ -1183,3 +1202,7 @@ def _test_Image_init_xform(imgtype): ...@@ -1183,3 +1202,7 @@ def _test_Image_init_xform(imgtype):
assert np.all(np.isclose(xform, rxform)) assert np.all(np.isclose(xform, rxform))
assert fsform_code == sform_code assert fsform_code == sform_code
assert fqform_code == qform_code assert fqform_code == qform_code
del fimg
del img
img = None
...@@ -347,8 +347,10 @@ def test_imcp_script_shouldPass(move=False): ...@@ -347,8 +347,10 @@ def test_imcp_script_shouldPass(move=False):
' '.join(infiles) ' '.join(infiles)
for inf in infiles: for inf in infiles:
img = nib.load(op.join(tindir, inf)) img = nib.load(op.join(tindir, inf),
mmap=False)
imghash = hash(img.get_data().tobytes()) imghash = hash(img.get_data().tobytes())
img = None
imageHashes.append(imghash) imageHashes.append(imghash)
print('adj files_to_expect: ', files_to_expect) print('adj files_to_expect: ', files_to_expect)
...@@ -357,7 +359,10 @@ def test_imcp_script_shouldPass(move=False): ...@@ -357,7 +359,10 @@ def test_imcp_script_shouldPass(move=False):
imcp_args[:-1] = [op.join(tindir, a) for a in imcp_args[:-1]] imcp_args[:-1] = [op.join(tindir, a) for a in imcp_args[:-1]]
imcp_args[ -1] = op.join(toutdir, imcp_args[-1]) imcp_args[ -1] = op.join(toutdir, imcp_args[-1])
imcp_args = [op.relpath(a, reldir) for a in imcp_args]
for i, a in enumerate(imcp_args):
if op.splitdrive(a)[0] == op.splitdrive(reldir)[0]:
imcp_args[i] = op.relpath(a, reldir)
print('indir before: ', os.listdir(tindir)) print('indir before: ', os.listdir(tindir))
print('outdir before: ', os.listdir(toutdir)) print('outdir before: ', os.listdir(toutdir))
...@@ -375,8 +380,6 @@ def test_imcp_script_shouldPass(move=False): ...@@ -375,8 +380,6 @@ def test_imcp_script_shouldPass(move=False):
# too hard if indir == outdir # too hard if indir == outdir
if move and tindir != toutdir: if move and tindir != toutdir:
real_print('indir: ', tindir)
real_print('outdir: ', toutdir)
infiles = os.listdir(tindir) infiles = os.listdir(tindir)
infiles = [f for f in infiles if op.isfile(f)] infiles = [f for f in infiles if op.isfile(f)]
infiles = [f for f in infiles if op.isfile(f)] infiles = [f for f in infiles if op.isfile(f)]
......
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