def checkFilesToExpect(files, outdir, outputType, datahashes): exts = { 'NIFTI' : ['.nii'], 'NIFTI_PAIR' : ['.hdr', '.img'], 'NIFTI_GZ' : ['.nii.gz'], '' : ['.nii.gz'], }.get(outputType, None) allFiles = [] if isinstance(files, str): files = files.split() for f in files: f, fe = fslimage.splitExt(f) fexts = exts if fexts is None: fexts = { '.img' : ['.hdr', '.img'], '.hdr' : ['.hdr', '.img'], '.nii' : ['.nii'], '.nii.gz' : ['.nii.gz'] }.get(fe, []) # filename already has a different extension elif fe != '' and fe not in fexts: fexts = [fe] for e in fexts: expected = op.join(outdir, f + e) allFiles.append(expected) print(' ', expected) assert op.exists(expected) allThatExist = os.listdir(outdir) allThatExist = [f for f in allThatExist if op.isfile(op.join(outdir, f))] assert len(allThatExist) == len(allFiles) for i, f in enumerate(files): f = fslimage.addExt(op.join(outdir, f), mustExist=True) if isinstance(datahashes, list): if len(datahashes) > len(files): diff = len(datahashes) - len(files) h = datahashes[i + diff] else: h = datahashes[i] else: h = datahashes[op.basename(f)] checkImageHash(f, h)
def test_splitExt(): exts = ['.nii.gz', '.nii', '.img', '.img.gz', '.hdr', '.hdr.gz'] for e in exts: prefix = 'blob' fname = '{}{}'.format(prefix, e) assert fslimage.splitExt(fname) == (prefix, e)
def saveOverlay(overlay, display=None): """Saves the currently selected overlay (only if it is a :class:`.Image`), by a call to :meth:`.Image.save`. If a ``display`` is provided, the :attr:`.Display.name` may be updated to match the new overlay file name. :arg overlay: The :class:`.Image` overlay to save :arg display: The :class:`.Display` instance associated with the overlay. """ import wx # TODO support for other overlay types if not isinstance(overlay, fslimage.Image): raise RuntimeError('Non-volumetric types not supported yet') # If this image has been loaded from a file, # ask the user whether they want to overwrite # that file, or save the image to a new file. # if overlay.dataSource is not None: # If the data source is not nifti (e.g. # mgz), we are not going to overwrite it, # so we don't ask. if fslimage.looksLikeImage(overlay.dataSource): msg = strings.messages['SaveOverlayAction.overwrite'].format( overlay.dataSource) title = strings.titles['SaveOverlayAction.overwrite'].format( overlay.dataSource) dlg = wx.MessageDialog(wx.GetTopLevelWindows()[0], message=msg, caption=title, style=(wx.ICON_WARNING | wx.YES_NO | wx.CANCEL | wx.NO_DEFAULT)) dlg.SetYesNoCancelLabels( strings.labels['SaveOverlayAction.overwrite'], strings.labels['SaveOverlayAction.saveNew'], strings.labels['SaveOverlayAction.cancel']) response = dlg.ShowModal() # Cancel == cancel the save # Yes == overwrite the existing file # No == save to a new file (prompt the user for the file name) if response == wx.ID_CANCEL: return if response == wx.ID_YES: doSave(overlay) return fromDir = op.dirname(overlay.dataSource) filename = fslimage.removeExt(op.basename(overlay.dataSource)) filename = '{}_copy'.format(filename) else: fromDir = fslsettings.read('loadSaveOverlayDir', os.getcwd()) if display is not None: filename = display.name else: filename = overlay.name filename = filename.replace('/', '_') filename = filename.replace('\\', '_') # Ask the user where they # want to save the image msg = strings.titles['SaveOverlayAction.saveFile'] dlg = wx.FileDialog(wx.GetApp().GetTopWindow(), message=msg, defaultDir=fromDir, defaultFile=filename, style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() != wx.ID_OK: return # Make sure that the user chose a supported # extension. If not, use the default extension. savePath = dlg.GetPath() prefix, suffix = fslimage.splitExt(savePath) if suffix == '': savePath = '{}{}'.format(prefix, fslimage.defaultExt()) oldPath = overlay.dataSource saveDir = op.dirname(savePath) if doSave(overlay, savePath): # Cache the save directory for next time. fslsettings.write('loadSaveOverlayDir', saveDir) # If image was in memory, or its old # name equalled the old datasource # base name, update its name. if oldPath is None or \ fslimage.removeExt(op.basename(oldPath)) == overlay.name: overlay.name = fslimage.removeExt(op.basename(savePath)) if display is not None: display.name = overlay.name
def imcp(src, dest, overwrite=False, useDefaultExt=False, move=False): """Copy the given ``src`` file to destination ``dest``. A :class:`.fsl.utils.path.PathError` is raised if anything goes wrong. :arg src: Path to copy. If ``allowedExts`` is provided, the file extension can be omitted. :arg dest: Destination path. Can be an incomplete file specification (i.e. without the extension), or a directory. :arg overwrite: If ``True`` this function will overwrite files that already exist. Defaults to ``False``. :arg useDefaultExt: Defaults to ``False``. If ``True``, the destination file type will be set according to the default extension, specified by :func:`~fsl.data.image.defaultExt`. If the source file does not have the same type as the default extension, it will be converted. If ``False``, the source file type is not changed. :arg move: If ``True``, the files are moved, instead of being copied. See :func:`immv`. """ import nibabel as nib if op.isdir(dest): dest = op.join(dest, op.basename(src)) srcBase, srcExt = fslimage.splitExt(src) destBase, destExt = fslimage.splitExt(dest) # src was specified without an # extension, or the specified # src does not have an allowed # extension. if srcExt == '': # Try to resolve the specified src # path - if src does not exist, or # does not have an allowed extension, # addExt will raise an error src = fslimage.addExt(src, mustExist=True) # We've resolved src to a # full filename - split it # again to get its extension srcBase, srcExt = fslimage.splitExt(src) if not op.exists(src): raise fslpath.PathError('imcp error - source path ' 'does not exist: {}'.format(src)) # Figure out the destination file # extension/type. If useDefaultExt # is True, we use the default # extension. Otherwise, if no # destination file extension is # provided, we use the source # extension. if useDefaultExt: destExt = fslimage.defaultExt() elif destExt == '': destExt = srcExt # Resolve any file group differences # e.g. we don't care if the src is # specified as file.hdr, and the dest # is specified as file.img - if src # and dest are part of the same file # group, we replace the dest extension # with the src extension. if srcExt != destExt: for group in fslimage.FILE_GROUPS: if srcExt in group and destExt in group: destExt = srcExt break dest = destBase + destExt # Give up if we don't have permission. if not os.access(op.dirname(dest), os.W_OK | os.X_OK): raise fslpath.PathError('imcp error - cannot write to {}'.format(dest)) if move and not os.access(op.dirname(src), os.W_OK | os.X_OK): raise fslpath.PathError('imcp error - cannot move from {}'.format(src)) # If the source file type does not # match the destination file type, # we need to perform a conversion. # # This is more expensive in terms of # io and cpu, but programmatically # very easy - nibabel does all the # hard work. if srcExt != destExt: if not overwrite and op.exists(dest): raise fslpath.PathError('imcp error - destination already ' 'exists ({})'.format(dest)) img = nib.load(src) nib.save(img, dest) if move: os.remove(src) return # Otherwise we do a file copy. This # is actually more complicated than # converting the file type due to # hdr/img pairs ... # # If the source is part of a file group, # e.g. src.img/src.hdr), we need to copy # the whole set of files. So here we # build a list of source files that need # to be copied/moved. The getFileGroup # function returns all other files that # are associated with this file (i.e. # part of the same group). # # We store the sources as separate # (base, ext) tuples, so we don't # have to re-split when creating # destination paths. # # The unambiguous flag tells getFileGroup # to raise an error if the source appears # to be part of an incopmlete file group # (e.g. file.hdr without an accompanying # file.img). copySrcs = fslpath.getFileGroup(src, fslimage.ALLOWED_EXTENSIONS, fslimage.FILE_GROUPS, fullPaths=False, unambiguous=True) copySrcs = [(srcBase, e) for e in copySrcs] # Build a list of destinations for each # copy source - we build this list in # advance, so we can fail if any of the # destinations already exist. We also # re-combine the source bases/extensions. copyDests = [destBase + e for (b, e) in copySrcs] copySrcs = [b + e for (b, e) in copySrcs] # Fail if any of the destination # paths already exist if not overwrite and any([op.exists(d) for d in copyDests]): raise fslpath.PathError('imcp error - a destination path already ' 'exists ({})'.format(', '.join(copyDests))) # Do the copy/move for src, dest in zip(copySrcs, copyDests): if move: shutil.move(src, dest) else: shutil.copy(src, dest)