Skip to content
Snippets Groups Projects
Commit 064608c6 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Python 2-3 compatibility.

parent 6685fea3
No related branches found
No related tags found
No related merge requests found
...@@ -100,7 +100,7 @@ log = logging.getLogger(__name__) ...@@ -100,7 +100,7 @@ log = logging.getLogger(__name__)
def listAtlases(refresh=False): def listAtlases(refresh=False):
"""Returns a dictionary containing :class:`AtlasDescription` objects for """Returns a list containing :class:`AtlasDescription` objects for
all available atlases. all available atlases.
:arg refresh: If ``True``, or if the atlas desriptions have not :arg refresh: If ``True``, or if the atlas desriptions have not
...@@ -119,7 +119,7 @@ def listAtlases(refresh=False): ...@@ -119,7 +119,7 @@ def listAtlases(refresh=False):
refresh = True refresh = True
if not refresh: if not refresh:
return ATLAS_DESCRIPTIONS.values() return list(ATLAS_DESCRIPTIONS.values())
atlasFiles = glob.glob(op.join(ATLAS_DIR, '*.xml')) atlasFiles = glob.glob(op.join(ATLAS_DIR, '*.xml'))
atlasDescs = map(AtlasDescription, atlasFiles) atlasDescs = map(AtlasDescription, atlasFiles)
...@@ -131,7 +131,7 @@ def listAtlases(refresh=False): ...@@ -131,7 +131,7 @@ def listAtlases(refresh=False):
desc.index = i desc.index = i
ATLAS_DESCRIPTIONS[desc.atlasID] = desc ATLAS_DESCRIPTIONS[desc.atlasID] = desc
return atlasDescs return list(atlasDescs)
def getAtlasDescription(atlasID): def getAtlasDescription(atlasID):
......
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
""" """
import os.path as op import os.path as op
import numpy as np import numpy as np
import image as fslimage from . import image as fslimage
import featresults from . import featresults
class FEATImage(fslimage.Image): class FEATImage(fslimage.Image):
......
...@@ -414,7 +414,7 @@ def loadClusterResults(featdir, settings, contrast): ...@@ -414,7 +414,7 @@ def loadClusterResults(featdir, settings, contrast):
# empty lines # empty lines
lines = f.readlines() lines = f.readlines()
lines = [l.strip() for l in lines] lines = [l.strip() for l in lines]
lines = filter(lambda l: l != '', lines) lines = [l for l in lines if l != '']
# the first line should contain column # the first line should contain column
# names, and each other line should # names, and each other line should
...@@ -554,19 +554,15 @@ def getEVNames(settings): ...@@ -554,19 +554,15 @@ def getEVNames(settings):
:arg settings: A FEAT settings dictionary (see :func:`loadSettings`). :arg settings: A FEAT settings dictionary (see :func:`loadSettings`).
""" """
numEVs = int(settings['evs_real']) numEVs = int(settings['evs_real'])
titleKeys = [s for s in settings.keys() if s.startswith('evtitle')]
derivKeys = [s for s in settings.keys() if s.startswith('deriv_yn')]
titleKeys = filter(lambda s: s.startswith('evtitle'), settings.keys()) def key(k):
derivKeys = filter(lambda s: s.startswith('deriv_yn'), settings.keys()) return int(''.join([c for c in k if c.isdigit()]))
def _cmp(key1, key2): titleKeys = sorted(titleKeys, key=key)
key1 = ''.join([c for c in key1 if c.isdigit()]) derivKeys = sorted(derivKeys, key=key)
key2 = ''.join([c for c in key2 if c.isdigit()])
return cmp(int(key1), int(key2))
titleKeys = sorted(titleKeys, cmp=_cmp)
derivKeys = sorted(derivKeys, cmp=_cmp)
evnames = [] evnames = []
for titleKey, derivKey in zip(titleKeys, derivKeys): for titleKey, derivKey in zip(titleKeys, derivKeys):
......
...@@ -38,6 +38,7 @@ import os ...@@ -38,6 +38,7 @@ import os
import os.path as op import os.path as op
import subprocess as sp import subprocess as sp
import six
import numpy as np import numpy as np
import nibabel as nib import nibabel as nib
...@@ -117,7 +118,7 @@ class Nifti1(object): ...@@ -117,7 +118,7 @@ class Nifti1(object):
header = header.copy() header = header.copy()
# The image parameter may be the name of an image file # The image parameter may be the name of an image file
if isinstance(image, basestring): if isinstance(image, six.string_types):
nibImage, filename = loadImage(addExt(image)) nibImage, filename = loadImage(addExt(image))
self.nibImage = nibImage self.nibImage = nibImage
...@@ -380,7 +381,7 @@ class Image(Nifti1, props.HasProperties): ...@@ -380,7 +381,7 @@ class Image(Nifti1, props.HasProperties):
# Or, if this image was loaded # Or, if this image was loaded
# from disk, use the file name # from disk, use the file name
elif isinstance(image, basestring): elif isinstance(image, six.string_types):
self.name = removeExt(op.basename(self.dataSource)) self.name = removeExt(op.basename(self.dataSource))
self.saved = True self.saved = True
...@@ -594,7 +595,7 @@ def looksLikeImage(filename, allowedExts=None): ...@@ -594,7 +595,7 @@ def looksLikeImage(filename, allowedExts=None):
# TODO A much more robust approach would be # TODO A much more robust approach would be
# to try loading the file using nibabel. # to try loading the file using nibabel.
return any(map(lambda ext: filename.endswith(ext), allowedExts)) return any([filename.endswith(ext) for ext in allowedExts])
def removeExt(filename): def removeExt(filename):
......
...@@ -14,8 +14,8 @@ import os.path as op ...@@ -14,8 +14,8 @@ import os.path as op
import props import props
import image as fslimage from . import image as fslimage
import melodicresults as melresults from . import melodicresults as melresults
class MelodicImage(fslimage.Image): class MelodicImage(fslimage.Image):
......
...@@ -21,6 +21,8 @@ import logging ...@@ -21,6 +21,8 @@ import logging
import os.path as op import os.path as op
import numpy as np import numpy as np
import six
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -43,7 +45,7 @@ class Model(object): ...@@ -43,7 +45,7 @@ class Model(object):
:arg indices: A list of indices into the vertex data. :arg indices: A list of indices into the vertex data.
""" """
if isinstance(data, basestring): if isinstance(data, six.string_types):
infile = data infile = data
data, lengths, indices = loadVTKPolydataFile(infile) data, lengths, indices = loadVTKPolydataFile(infile)
...@@ -131,6 +133,7 @@ def loadVTKPolydataFile(infile): ...@@ -131,6 +133,7 @@ def loadVTKPolydataFile(infile):
for i in range(nVertices): for i in range(nVertices):
vertLine = lines[i + 5] vertLine = lines[i + 5]
vertices[i, :] = map(float, vertLine.split()) vertices[i, :] = map(float, vertLine.split())
vertices[i, :] = [float(w) for w in vertLine.split()]
indexOffset = 0 indexOffset = 0
for i in range(nPolygons): for i in range(nPolygons):
...@@ -141,6 +144,7 @@ def loadVTKPolydataFile(infile): ...@@ -141,6 +144,7 @@ def loadVTKPolydataFile(infile):
start = indexOffset start = indexOffset
end = indexOffset + polygonLengths[i] end = indexOffset + polygonLengths[i]
indices[start:end] = map(int, polyLine[1:]) indices[start:end] = map(int, polyLine[1:])
indices[start:end] = [int(w) for w in polyLine[1:]]
indexOffset += polygonLengths[i] indexOffset += polygonLengths[i]
......
...@@ -9,12 +9,14 @@ the diffusion tensor data generated by the FSL ``dtifit`` tool. ...@@ -9,12 +9,14 @@ the diffusion tensor data generated by the FSL ``dtifit`` tool.
""" """
import logging import logging
import re import re
import glob import glob
import os.path as op import os.path as op
import fsl.data.image as fslimage import six
from . import image as fslimage
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -101,7 +103,7 @@ class TensorImage(fslimage.Nifti1): ...@@ -101,7 +103,7 @@ class TensorImage(fslimage.Nifti1):
eigenvalues. eigenvalues.
""" """
dtifitDir = isinstance(path, basestring) dtifitDir = isinstance(path, six.string_types)
if dtifitDir: if dtifitDir:
......
...@@ -33,11 +33,12 @@ the task (via :func:`idle`). ...@@ -33,11 +33,12 @@ the task (via :func:`idle`).
import time import time
import Queue
import logging import logging
import threading import threading
import collections import collections
try: import queue
except: import Queue as queue
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -114,7 +115,7 @@ in the :func:`idle` function. ...@@ -114,7 +115,7 @@ in the :func:`idle` function.
""" """
_idleQueue = Queue.Queue() _idleQueue = queue.Queue()
"""A ``Queue`` of functions which are to be run on the ``wx.EVT_IDLE`` """A ``Queue`` of functions which are to be run on the ``wx.EVT_IDLE``
loop. loop.
""" """
...@@ -129,7 +130,7 @@ def _wxIdleLoop(ev): ...@@ -129,7 +130,7 @@ def _wxIdleLoop(ev):
try: try:
task, schedtime, timeout, args, kwargs = _idleQueue.get_nowait() task, schedtime, timeout, args, kwargs = _idleQueue.get_nowait()
except Queue.Empty: except queue.Empty:
return return
name = getattr(task, '__name__', '<unknown>') name = getattr(task, '__name__', '<unknown>')
......
...@@ -22,7 +22,7 @@ import threading ...@@ -22,7 +22,7 @@ import threading
import wx import wx
from fsl.utils.platform import platform as fslplatform from .platform import platform as fslplatform
class SimpleMessageDialog(wx.Dialog): class SimpleMessageDialog(wx.Dialog):
...@@ -455,7 +455,12 @@ class TextEditDialog(wx.Dialog): ...@@ -455,7 +455,12 @@ class TextEditDialog(wx.Dialog):
if icon is not None: if icon is not None:
icon = wx.ArtProvider.GetMessageBoxIcon(icon) icon = wx.ArtProvider.GetMessageBoxIcon(icon)
bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
if fslplatform.wxFlavour == fslplatform.WX_PHOENIX:
bmp = wx.Bitmap()
else:
bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
bmp.CopyFromIcon(icon) bmp.CopyFromIcon(icon)
self.__icon = wx.StaticBitmap(self) self.__icon = wx.StaticBitmap(self)
self.__icon.SetBitmap(bmp) self.__icon.SetBitmap(bmp)
...@@ -634,7 +639,12 @@ class FSLDirDialog(wx.Dialog): ...@@ -634,7 +639,12 @@ class FSLDirDialog(wx.Dialog):
self.__skip = wx.Button( self, id=wx.ID_CANCEL) self.__skip = wx.Button( self, id=wx.ID_CANCEL)
icon = wx.ArtProvider.GetMessageBoxIcon(wx.ICON_EXCLAMATION) icon = wx.ArtProvider.GetMessageBoxIcon(wx.ICON_EXCLAMATION)
bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
if fslplatform.wxFlavour == fslplatform.WX_PYTHON:
bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
else:
bmp = wx.Bitmap()
bmp.CopyFromIcon(icon) bmp.CopyFromIcon(icon)
self.__icon.SetBitmap(bmp) self.__icon.SetBitmap(bmp)
...@@ -756,7 +766,12 @@ class CheckBoxMessageDialog(wx.Dialog): ...@@ -756,7 +766,12 @@ class CheckBoxMessageDialog(wx.Dialog):
if icon is not None: if icon is not None:
icon = wx.ArtProvider.GetMessageBoxIcon(icon) icon = wx.ArtProvider.GetMessageBoxIcon(icon)
self.__icon = wx.StaticBitmap(self) self.__icon = wx.StaticBitmap(self)
bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
if fslplatform.wxFlavour == fslplatform.WX_PYTHON:
bmp = wx.EmptyBitmap(icon.GetWidth(), icon.GetHeight())
else:
bmp = wx.Bitmap()
bmp.CopyFromIcon(icon) bmp.CopyFromIcon(icon)
self.__icon.SetBitmap(bmp) self.__icon.SetBitmap(bmp)
else: else:
......
...@@ -12,12 +12,18 @@ import logging ...@@ -12,12 +12,18 @@ import logging
import wx import wx
from fsl.utils.platform import platform as fslplatform
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class ImagePanel(wx.PyPanel): if fslplatform.wxFlavour == fslplatform.WX_PHOENIX: ImagePanelBase = wx.Panel
"""A :class:`wx.PyPanel` which may be used to display a resizeable else: ImagePanelBase = wx.PyPanel
class ImagePanel(ImagePanelBase):
"""A :class:`wx.Panel` which may be used to display a resizeable
:class:`wx.Image`. The image is scaled to the size of the panel. :class:`wx.Image`. The image is scaled to the size of the panel.
""" """
...@@ -32,7 +38,7 @@ class ImagePanel(wx.PyPanel): ...@@ -32,7 +38,7 @@ class ImagePanel(wx.PyPanel):
:arg image: The :class:`wx.Image` object to display. :arg image: The :class:`wx.Image` object to display.
""" """
wx.PyPanel.__init__(self, parent) ImagePanelBase.__init__(self, parent)
self.Bind(wx.EVT_PAINT, self.Draw) self.Bind(wx.EVT_PAINT, self.Draw)
self.Bind(wx.EVT_SIZE, self.__onSize) self.Bind(wx.EVT_SIZE, self.__onSize)
...@@ -46,6 +52,11 @@ class ImagePanel(wx.PyPanel): ...@@ -46,6 +52,11 @@ class ImagePanel(wx.PyPanel):
:arg image: The :class:`wx.Image` object to display. :arg image: The :class:`wx.Image` object to display.
""" """
self.__image = image self.__image = image
if image is not None: self.SetMinSize(image.GetSize())
else: self.SetMinSize((0, 0))
self.Refresh() self.Refresh()
...@@ -86,6 +97,6 @@ class ImagePanel(wx.PyPanel): ...@@ -86,6 +97,6 @@ class ImagePanel(wx.PyPanel):
if width == 0 or height == 0: if width == 0 or height == 0:
return return
bitmap = wx.BitmapFromImage(self.__image.Scale(width, height)) bitmap = self.__image.Scale(width, height).ConvertToBitmap()
dc.DrawBitmap(bitmap, 0, 0, False) dc.DrawBitmap(bitmap, 0, 0, False)
...@@ -18,6 +18,7 @@ a function: ...@@ -18,6 +18,7 @@ a function:
import hashlib import hashlib
import functools import functools
import six
def memoizeMD5(func): def memoizeMD5(func):
...@@ -35,7 +36,8 @@ def memoizeMD5(func): ...@@ -35,7 +36,8 @@ def memoizeMD5(func):
hashobj = hashlib.md5() hashobj = hashlib.md5()
for arg in args: for arg in args:
hashobj.update(str(arg)) arg = six.u(arg).encode('utf-8')
hashobj.update(arg)
digest = hashobj.hexdigest() digest = hashobj.hexdigest()
cached = cache.get(digest) cached = cache.get(digest)
......
...@@ -34,7 +34,7 @@ class Notifier(object): ...@@ -34,7 +34,7 @@ class Notifier(object):
"""Initialises a dictionary of listeners on a new ``Notifier`` """Initialises a dictionary of listeners on a new ``Notifier``
instance. instance.
""" """
new = object.__new__(cls, *args, **kwargs) new = object.__new__(cls)
new.__listeners = collections.OrderedDict() new.__listeners = collections.OrderedDict()
return new return new
......
...@@ -91,8 +91,8 @@ def addExt(prefix, allowedExts, mustExist=True, defaultExt=None): ...@@ -91,8 +91,8 @@ def addExt(prefix, allowedExts, mustExist=True, defaultExt=None):
if not mustExist: if not mustExist:
# the provided file name already # the provided file name already
# ends with a supported extension # ends with a supported extension
if any(map(lambda ext: prefix.endswith(ext), allowedExts)): if any([prefix.endswith(ext) for ext in allowedExts]):
return prefix return prefix
if defaultExt is not None: return prefix + defaultExt if defaultExt is not None: return prefix + defaultExt
...@@ -100,16 +100,16 @@ def addExt(prefix, allowedExts, mustExist=True, defaultExt=None): ...@@ -100,16 +100,16 @@ def addExt(prefix, allowedExts, mustExist=True, defaultExt=None):
# If the provided prefix already ends with a # If the provided prefix already ends with a
# supported extension , check to see that it exists # supported extension , check to see that it exists
if any(map(lambda ext: prefix.endswith(ext), allowedExts)): if any([prefix.endswith(ext) for ext in allowedExts]):
extended = [prefix] extended = [prefix]
# Otherwise, make a bunch of file names, one per # Otherwise, make a bunch of file names, one per
# supported extension, and test to see if exactly # supported extension, and test to see if exactly
# one of them exists. # one of them exists.
else: else:
extended = map(lambda ext: prefix + ext, allowedExts) extended = [prefix + ext for ext in allowedExts]
exists = map(op.isfile, extended) exists = [op.isfile(e) for e in extended]
# Could not find any supported file # Could not find any supported file
# with the specified prefix # with the specified prefix
...@@ -119,7 +119,7 @@ def addExt(prefix, allowedExts, mustExist=True, defaultExt=None): ...@@ -119,7 +119,7 @@ def addExt(prefix, allowedExts, mustExist=True, defaultExt=None):
# Ambiguity! More than one supported # Ambiguity! More than one supported
# file with the specified prefix # file with the specified prefix
if len(filter(bool, exists)) > 1: if sum(exists) > 1:
raise ValueError('More than one file with prefix {}'.format(prefix)) raise ValueError('More than one file with prefix {}'.format(prefix))
# Return the full file name of the # Return the full file name of the
...@@ -139,7 +139,7 @@ def removeExt(filename, allowedExts): ...@@ -139,7 +139,7 @@ def removeExt(filename, allowedExts):
""" """
# figure out the extension of the given file # figure out the extension of the given file
extMatches = map(lambda ext: filename.endswith(ext), allowedExts) extMatches = [filename.endswith(ext) for ext in allowedExts]
# the file does not have a supported extension # the file does not have a supported extension
if not any(extMatches): if not any(extMatches):
......
...@@ -8,17 +8,14 @@ ...@@ -8,17 +8,14 @@
of information about the current platform we are running on. A single of information about the current platform we are running on. A single
``Platform`` instance is created when this module is first imported, and ``Platform`` instance is created when this module is first imported, and
is available as a module attribute called :attr:`platform`. is available as a module attribute called :attr:`platform`.
.. note:: The ``Platform`` class only contains information which is not
already accessible from the built-in ``platform`` module
(e.g. operating system information), or the ``six`` module (e.g.
python 2 vs 3).
""" """
import logging import logging
import os import os
import sys
import platform as builtin_platform
import fsl.utils.notifier as notifier import fsl.utils.notifier as notifier
...@@ -67,6 +64,8 @@ class Platform(notifier.Notifier): ...@@ -67,6 +64,8 @@ class Platform(notifier.Notifier):
.. autosummary:: .. autosummary::
os
frozen
fsldir fsldir
haveGui haveGui
wxPlatform wxPlatform
...@@ -125,6 +124,22 @@ class Platform(notifier.Notifier): ...@@ -125,6 +124,22 @@ class Platform(notifier.Notifier):
log.warning('Could not determine wx platform from ' log.warning('Could not determine wx platform from '
'information: {}'.format(pi)) 'information: {}'.format(pi))
@property
def os(self):
"""The operating system name. Whatever is returned by the built-in
``platform.system`` function.
"""
return builtin_platform.system()
@property
def frozen(self):
"""``True`` if we are running in a compiled/frozen application,
``False`` otherwise.
"""
return getattr(sys, 'frozen', False)
@property @property
def haveGui(self): def haveGui(self):
......
...@@ -26,7 +26,9 @@ import logging ...@@ -26,7 +26,9 @@ import logging
import subprocess as subp import subprocess as subp
import threading as thread import threading as thread
import Queue as queue
try: import queue
except: import Queue as queue
import wx import wx
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
""" """
import six
import collections import collections
...@@ -164,7 +166,7 @@ class TypeDict(object): ...@@ -164,7 +166,7 @@ class TypeDict(object):
string, or a combination of strings and types, into a tuple. string, or a combination of strings and types, into a tuple.
""" """
if isinstance(key, basestring): if isinstance(key, six.string_types):
if '.' in key: return tuple(key.split('.')) if '.' in key: return tuple(key.split('.'))
else: return key else: return key
...@@ -174,7 +176,7 @@ class TypeDict(object): ...@@ -174,7 +176,7 @@ class TypeDict(object):
key = [] key = []
for tk in tKeys: for tk in tKeys:
if isinstance(tk, basestring): key.append(tk) if isinstance(tk, six.string_types): key.append(tk)
elif isinstance(tk, collections.Sequence): key += list(tk) elif isinstance(tk, collections.Sequence): key += list(tk)
else: key.append(tk) else: key.append(tk)
......
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