From a763e5d1b3921b3194f3d4e94ab9de3fbe08bbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Picca=20Fr=C3=A9d=C3=A9ric-Emmanuel?= Date: Tue, 28 May 2019 08:16:16 +0200 Subject: New upstream version 0.10.1+dfsg --- silx/gui/dialog/AbstractDataFileDialog.py | 56 +++-- silx/gui/dialog/ColormapDialog.py | 355 +++++++++++++++++++-------- silx/gui/dialog/DataFileDialog.py | 10 +- silx/gui/dialog/FileTypeComboBox.py | 39 ++- silx/gui/dialog/ImageFileDialog.py | 5 +- silx/gui/dialog/SafeFileSystemModel.py | 6 +- silx/gui/dialog/test/test_colormapdialog.py | 36 +-- silx/gui/dialog/test/test_datafiledialog.py | 115 +++------ silx/gui/dialog/test/test_imagefiledialog.py | 117 +++------ silx/gui/dialog/utils.py | 6 +- 10 files changed, 394 insertions(+), 351 deletions(-) (limited to 'silx/gui/dialog') diff --git a/silx/gui/dialog/AbstractDataFileDialog.py b/silx/gui/dialog/AbstractDataFileDialog.py index 40045fe..c660cd7 100644 --- a/silx/gui/dialog/AbstractDataFileDialog.py +++ b/silx/gui/dialog/AbstractDataFileDialog.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2016 European Synchrotron Radiation Facility +# Copyright (c) 2016-2018 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -28,29 +28,36 @@ This module contains an :class:`AbstractDataFileDialog`. __authors__ = ["V. Valls"] __license__ = "MIT" -__date__ = "05/03/2018" +__date__ = "03/12/2018" import sys import os import logging -import numpy import functools +from distutils.version import LooseVersion + +import numpy +import six + import silx.io.url from silx.gui import qt from silx.gui.hdf5.Hdf5TreeModel import Hdf5TreeModel from . import utils -from silx.third_party import six from .FileTypeComboBox import FileTypeComboBox -try: - import fabio -except ImportError: - fabio = None + +import fabio _logger = logging.getLogger(__name__) +DEFAULT_SIDEBAR_URL = True +"""Set it to false to disable initilializing of the sidebar urls with the +default Qt list. This could allow to disable a behaviour known to segfault on +some version of PyQt.""" + + class _IconProvider(object): FileDialogToParentDir = qt.QStyle.SP_CustomBase + 1 @@ -143,14 +150,22 @@ class _SideBar(qt.QListView): :rtype: List[str] """ urls = [] - if qt.qVersion().startswith("5.") and sys.platform in ["linux", "linux2"]: + version = LooseVersion(qt.qVersion()) + feed_sidebar = True + + if not DEFAULT_SIDEBAR_URL: + _logger.debug("Skip default sidebar URLs (from setted variable)") + feed_sidebar = False + elif version.version[0] == 4 and sys.platform in ["win32"]: + # Avoid locking the GUI 5min in case of use of network driver + _logger.debug("Skip default sidebar URLs (avoid lock when using network drivers)") + feed_sidebar = False + elif version < LooseVersion("5.11.2") and qt.BINDING == "PyQt5" and sys.platform in ["linux", "linux2"]: # Avoid segfault on PyQt5 + gtk _logger.debug("Skip default sidebar URLs (avoid PyQt5 segfault)") - pass - elif qt.qVersion().startswith("4.") and sys.platform in ["win32"]: - # Avoid 5min of locked GUI relative to network driver - _logger.debug("Skip default sidebar URLs (avoid lock when using network drivers)") - else: + feed_sidebar = False + + if feed_sidebar: # Get default shortcut # There is no other way d = qt.QFileDialog(self) @@ -1061,8 +1076,6 @@ class AbstractDataFileDialog(qt.QDialog): def __openFabioFile(self, filename): self.__closeFile() try: - if fabio is None: - raise ImportError("Fabio module is not available") self.__fabio = fabio.open(filename) self.__openedFiles.append(self.__fabio) self.__selectedFile = filename @@ -1108,10 +1121,10 @@ class AbstractDataFileDialog(qt.QDialog): if codec.is_autodetect(): if self.__isSilxHavePriority(filename): openners.append(self.__openSilxFile) - if fabio is not None and self._isFabioFilesSupported(): + if self._isFabioFilesSupported(): openners.append(self.__openFabioFile) else: - if fabio is not None and self._isFabioFilesSupported(): + if self._isFabioFilesSupported(): openners.append(self.__openFabioFile) openners.append(self.__openSilxFile) elif codec.is_silx_codec(): @@ -1159,10 +1172,9 @@ class AbstractDataFileDialog(qt.QDialog): is_fabio_have_priority = not codec.is_silx_codec() and not self.__isSilxHavePriority(path) if is_fabio_decoder or is_fabio_have_priority: # Then it's flat frame container - if fabio is not None: - self.__openFabioFile(path) - if self.__fabio is not None: - selectedData = _FabioData(self.__fabio) + self.__openFabioFile(path) + if self.__fabio is not None: + selectedData = _FabioData(self.__fabio) else: assert(False) diff --git a/silx/gui/dialog/ColormapDialog.py b/silx/gui/dialog/ColormapDialog.py index cbbfa5a..9950ad4 100644 --- a/silx/gui/dialog/ColormapDialog.py +++ b/silx/gui/dialog/ColormapDialog.py @@ -63,9 +63,10 @@ from __future__ import division __authors__ = ["V.A. Sole", "T. Vincent", "H. Payno"] __license__ = "MIT" -__date__ = "23/05/2018" +__date__ = "27/11/2018" +import enum import logging import numpy @@ -73,10 +74,10 @@ import numpy from .. import qt from ..colors import Colormap, preferredColormaps from ..plot import PlotWidget +from ..plot.items.axis import Axis from silx.gui.widgets.FloatEdit import FloatEdit import weakref from silx.math.combo import min_max -from silx.third_party import enum from silx.gui import icons from silx.math.histogram import Histogramnd @@ -154,39 +155,59 @@ class _ColormapNameCombox(qt.QComboBox): qt.QComboBox.__init__(self, parent) self.__initItems() - ORIGINAL_NAME = qt.Qt.UserRole + 1 + LUT_NAME = qt.Qt.UserRole + 1 + LUT_COLORS = qt.Qt.UserRole + 2 def __initItems(self): for colormapName in preferredColormaps(): index = self.count() self.addItem(str.title(colormapName)) - self.setItemIcon(index, self.getIconPreview(colormapName)) - self.setItemData(index, colormapName, role=self.ORIGINAL_NAME) + self.setItemIcon(index, self.getIconPreview(name=colormapName)) + self.setItemData(index, colormapName, role=self.LUT_NAME) - def getIconPreview(self, colormapName): + def getIconPreview(self, name=None, colors=None): """Return an icon preview from a LUT name. This icons are cached into a global structure. - :param str colormapName: str + :param str name: Name of the LUT + :param numpy.ndarray colors: Colors identify the LUT :rtype: qt.QIcon """ - if colormapName not in _colormapIconPreview: - icon = self.createIconPreview(colormapName) - _colormapIconPreview[colormapName] = icon - return _colormapIconPreview[colormapName] - - def createIconPreview(self, colormapName): + if name is not None: + iconKey = name + else: + iconKey = tuple(colors) + icon = _colormapIconPreview.get(iconKey, None) + if icon is None: + icon = self.createIconPreview(name, colors) + _colormapIconPreview[iconKey] = icon + return icon + + def createIconPreview(self, name=None, colors=None): """Create and return an icon preview from a LUT name. This icons are cached into a global structure. - :param str colormapName: Name of the LUT + :param str name: Name of the LUT + :param numpy.ndarray colors: Colors identify the LUT :rtype: qt.QIcon """ - colormap = Colormap(colormapName) + colormap = Colormap(name) size = 32 - lut = colormap.getNColors(size) + if name is not None: + lut = colormap.getNColors(size) + else: + lut = colors + if len(lut) > size: + # Down sample + step = int(len(lut) / size) + lut = lut[::step] + elif len(lut) < size: + # Over sample + indexes = numpy.arange(size) / float(size) * (len(lut) - 1) + indexes = indexes.astype("int") + lut = lut[indexes] if lut is None or len(lut) == 0: return qt.QIcon() @@ -204,18 +225,50 @@ class _ColormapNameCombox(qt.QComboBox): return qt.QIcon(pixmap) def getCurrentName(self): - return self.itemData(self.currentIndex(), self.ORIGINAL_NAME) + return self.itemData(self.currentIndex(), self.LUT_NAME) + + def getCurrentColors(self): + return self.itemData(self.currentIndex(), self.LUT_COLORS) + + def findLutName(self, name): + return self.findData(name, role=self.LUT_NAME) + + def findLutColors(self, lut): + for index in range(self.count()): + if self.itemData(index, role=self.LUT_NAME) is not None: + continue + colors = self.itemData(index, role=self.LUT_COLORS) + if colors is None: + continue + if numpy.array_equal(colors, lut): + return index + return -1 + + def setCurrentLut(self, colormap): + name = colormap.getName() + if name is not None: + self._setCurrentName(name) + else: + lut = colormap.getColormapLUT() + self._setCurrentLut(lut) - def findColormap(self, name): - return self.findData(name, role=self.ORIGINAL_NAME) + def _setCurrentLut(self, lut): + index = self.findLutColors(lut) + if index == -1: + index = self.count() + self.addItem("Custom") + self.setItemIcon(index, self.getIconPreview(colors=lut)) + self.setItemData(index, None, role=self.LUT_NAME) + self.setItemData(index, lut, role=self.LUT_COLORS) + self.setCurrentIndex(index) - def setCurrentName(self, name): - index = self.findColormap(name) + def _setCurrentName(self, name): + index = self.findLutName(name) if index < 0: index = self.count() self.addItem(str.title(name)) - self.setItemIcon(index, self.getIconPreview(name)) - self.setItemData(index, name, role=self.ORIGINAL_NAME) + self.setItemIcon(index, self.getIconPreview(name=name)) + self.setItemData(index, name, role=self.LUT_NAME) self.setCurrentIndex(index) @@ -255,6 +308,7 @@ class ColormapDialog(qt.QDialog): the self.setcolormap is a callback) """ + self.__displayInvalidated = False self._histogramData = None self._minMaxWasEdited = False self._initialRange = None @@ -276,20 +330,19 @@ class ColormapDialog(qt.QDialog): # Colormap row self._comboBoxColormap = _ColormapNameCombox(parent=formWidget) - self._comboBoxColormap.currentIndexChanged[int].connect(self._updateName) + self._comboBoxColormap.currentIndexChanged[int].connect(self._updateLut) formLayout.addRow('Colormap:', self._comboBoxColormap) # Normalization row self._normButtonLinear = qt.QRadioButton('Linear') self._normButtonLinear.setChecked(True) self._normButtonLog = qt.QRadioButton('Log') - self._normButtonLog.toggled.connect(self._activeLogNorm) normButtonGroup = qt.QButtonGroup(self) normButtonGroup.setExclusive(True) normButtonGroup.addButton(self._normButtonLinear) normButtonGroup.addButton(self._normButtonLog) - self._normButtonLinear.toggled[bool].connect(self._updateLinearNorm) + normButtonGroup.buttonClicked[qt.QAbstractButton].connect(self._updateNormalization) normLayout = qt.QHBoxLayout() normLayout.setContentsMargins(0, 0, 0, 0) @@ -388,9 +441,17 @@ class ColormapDialog(qt.QDialog): self.setFixedSize(self.sizeHint()) self._applyColormap() + def _displayLater(self): + self.__displayInvalidated = True + def showEvent(self, event): self.visibleChanged.emit(True) super(ColormapDialog, self).showEvent(event) + if self.isVisible(): + if self.__displayInvalidated: + self._applyColormap() + self._updateDataInPlot() + self.__displayInvalidated = False def closeEvent(self, event): if not self.isModal(): @@ -434,6 +495,54 @@ class ColormapDialog(qt.QDialog): def sizeHint(self): return self.layout().minimumSize() + def _computeView(self, dataMin, dataMax): + """Compute the location of the view according to the bound of the data + + :rtype: Tuple(float, float) + """ + marginRatio = 1.0 / 6.0 + scale = self._plot.getXAxis().getScale() + + if self._dataRange is not None: + if scale == Axis.LOGARITHMIC: + minRange = self._dataRange[1] + else: + minRange = self._dataRange[0] + maxRange = self._dataRange[2] + if minRange is not None: + dataMin = min(dataMin, minRange) + dataMax = max(dataMax, maxRange) + + if self._histogramData is not None: + info = min_max(self._histogramData[1]) + if scale == Axis.LOGARITHMIC: + minHisto = info.min_positive + else: + minHisto = info.minimum + maxHisto = info.maximum + if minHisto is not None: + dataMin = min(dataMin, minHisto) + dataMax = max(dataMax, maxHisto) + + if scale == Axis.LOGARITHMIC: + epsilon = numpy.finfo(numpy.float32).eps + if dataMin == 0: + dataMin = epsilon + if dataMax < dataMin: + dataMax = dataMin + epsilon + marge = marginRatio * abs(numpy.log10(dataMax) - numpy.log10(dataMin)) + viewMin = 10**(numpy.log10(dataMin) - marge) + viewMax = 10**(numpy.log10(dataMax) + marge) + else: # scale == Axis.LINEAR: + marge = marginRatio * abs(dataMax - dataMin) + if marge < 0.0001: + # Smaller that the QLineEdit precision + marge = 0.0001 + viewMin = dataMin - marge + viewMax = dataMax + marge + + return viewMin, viewMax + def _plotUpdate(self, updateMarkers=True): """Update the plot content @@ -454,27 +563,8 @@ class ColormapDialog(qt.QDialog): if minData > maxData: # avoid a full collapse minData, maxData = maxData, minData - minimum = minData - maximum = maxData - - if self._dataRange is not None: - minRange = self._dataRange[0] - maxRange = self._dataRange[2] - minimum = min(minimum, minRange) - maximum = max(maximum, maxRange) - if self._histogramData is not None: - minHisto = self._histogramData[1][0] - maxHisto = self._histogramData[1][-1] - minimum = min(minimum, minHisto) - maximum = max(maximum, maxHisto) - - marge = abs(maximum - minimum) / 6.0 - if marge < 0.0001: - # Smaller that the QLineEdit precision - marge = 0.0001 - - minView, maxView = minimum - marge, maximum + marge + minView, maxView = self._computeView(minData, maxData) if updateMarkers: # Save the state in we are not moving the markers @@ -483,6 +573,9 @@ class ColormapDialog(qt.QDialog): minView = min(minView, self._initialRange[0]) maxView = max(maxView, self._initialRange[1]) + if minView > minData: + # Hide the min range + minData = minView x = [minView, minData, maxData, maxView] y = [0, 0, 1, 1] @@ -493,26 +586,37 @@ class ColormapDialog(qt.QDialog): linestyle='-', resetzoom=False) + scale = self._plot.getXAxis().getScale() + if updateMarkers: - minDraggable = (self._colormap().isEditable() and - not self._minValue.isAutoChecked()) - self._plot.addXMarker( - self._minValue.getFiniteValue(), - legend='Min', - text='Min', - draggable=minDraggable, - color='blue', - constraint=self._plotMinMarkerConstraint) - - maxDraggable = (self._colormap().isEditable() and - not self._maxValue.isAutoChecked()) - self._plot.addXMarker( - self._maxValue.getFiniteValue(), - legend='Max', - text='Max', - draggable=maxDraggable, - color='blue', - constraint=self._plotMaxMarkerConstraint) + posMin = self._minValue.getFiniteValue() + posMax = self._maxValue.getFiniteValue() + + def isDisplayable(pos): + if scale == Axis.LOGARITHMIC: + return pos > 0.0 + return True + + if isDisplayable(posMin): + minDraggable = (self._colormap().isEditable() and + not self._minValue.isAutoChecked()) + self._plot.addXMarker( + posMin, + legend='Min', + text='Min', + draggable=minDraggable, + color='blue', + constraint=self._plotMinMarkerConstraint) + if isDisplayable(posMax): + maxDraggable = (self._colormap().isEditable() and + not self._maxValue.isAutoChecked()) + self._plot.addXMarker( + posMax, + legend='Max', + text='Max', + draggable=maxDraggable, + color='blue', + constraint=self._plotMaxMarkerConstraint) self._plot.resetZoom() @@ -546,7 +650,7 @@ class ColormapDialog(qt.QDialog): """Compute the data range as used by :meth:`setDataRange`. :param data: The data to process - :rtype: Tuple(float, float, float) + :rtype: List[Union[None,float]] """ if data is None or len(data) == 0: return None, None, None @@ -558,8 +662,6 @@ class ColormapDialog(qt.QDialog): if dataRange is not None: min_positive = dataRange.min_positive - if min_positive is None: - min_positive = float('nan') dataRange = dataRange.minimum, min_positive, dataRange.maximum if dataRange is None or len(dataRange) != 3: @@ -571,7 +673,7 @@ class ColormapDialog(qt.QDialog): return dataRange @staticmethod - def computeHistogram(data): + def computeHistogram(data, scale=Axis.LINEAR): """Compute the data histogram as used by :meth:`setHistogram`. :param data: The data to process @@ -588,7 +690,12 @@ class ColormapDialog(qt.QDialog): if len(_data) == 0: return None, None + if scale == Axis.LOGARITHMIC: + _data = numpy.log10(_data) xmin, xmax = min_max(_data, min_positive=False, finite=True) + if xmin is None: + return None, None + nbins = min(256, int(numpy.sqrt(_data.size))) data_range = xmin, xmax @@ -601,7 +708,10 @@ class ColormapDialog(qt.QDialog): _data = _data.ravel().astype(numpy.float32) histogram = Histogramnd(_data, n_bins=nbins, histo_range=data_range) - return histogram.histo, histogram.edges[0] + bins = histogram.edges[0] + if scale == Axis.LOGARITHMIC: + bins = 10**bins + return histogram.histo, bins def _getData(self): if self._data is None: @@ -624,7 +734,10 @@ class ColormapDialog(qt.QDialog): else: self._data = weakref.ref(data, self._dataAboutToFinalize) - self._updateDataInPlot() + if self.isVisible(): + self._updateDataInPlot() + else: + self._displayLater() def _setDataInPlotMode(self, mode): if self._dataInPlotMode == mode: @@ -660,10 +773,15 @@ class ColormapDialog(qt.QDialog): self.setDataRange(*result) elif mode == _DataInPlotMode.HISTOGRAM: # The histogram should be done in a worker thread - result = self.computeHistogram(data) + result = self.computeHistogram(data, scale=self._plot.getXAxis().getScale()) self.setHistogram(*result) self.setDataRange() + def _invalidateHistogram(self): + """Recompute the histogram if it is displayed""" + if self._dataInPlotMode == _DataInPlotMode.HISTOGRAM: + self._updateDataInPlot() + def _colormapAboutToFinalize(self, weakrefColormap): """Callback when the data weakref is about to be finalized.""" if self._colormap is weakrefColormap: @@ -727,9 +845,9 @@ class ColormapDialog(qt.QDialog): """ colormap = self.getColormap() if colormap is not None and self._colormapStoredState is not None: - if self._colormap()._toDict() != self._colormapStoredState: + if colormap != self._colormapStoredState: self._ignoreColormapChange = True - colormap._setFromDict(self._colormapStoredState) + colormap.setFromColormap(self._colormapStoredState) self._ignoreColormapChange = False self._applyColormap() @@ -740,12 +858,18 @@ class ColormapDialog(qt.QDialog): :param float positiveMin: The positive minimum of the data :param float maximum: The maximum of the data """ - if minimum is None or positiveMin is None or maximum is None: + scale = self._plot.getXAxis().getScale() + if scale == Axis.LOGARITHMIC: + dataMin, dataMax = positiveMin, maximum + else: + dataMin, dataMax = minimum, maximum + + if dataMin is None or dataMax is None: self._dataRange = None self._plot.remove(legend='Range', kind='histogram') else: hist = numpy.array([1]) - bin_edges = numpy.array([minimum, maximum]) + bin_edges = numpy.array([dataMin, dataMax]) self._plot.addHistogram(hist, bin_edges, legend="Range", @@ -801,7 +925,7 @@ class ColormapDialog(qt.QDialog): """ colormap = self.getColormap() if colormap is not None: - self._colormapStoredState = colormap._toDict() + self._colormapStoredState = colormap.copy() else: self._colormapStoredState = None @@ -830,8 +954,11 @@ class ColormapDialog(qt.QDialog): self._colormap = colormap self.storeCurrentState() - self._updateResetButton() - self._applyColormap() + if self.isVisible(): + self._applyColormap() + else: + self._updateResetButton() + self._displayLater() def _updateResetButton(self): resetButton = self._buttonsNonModal.button(qt.QDialogButtonBox.Reset) @@ -839,7 +966,7 @@ class ColormapDialog(qt.QDialog): colormap = self.getColormap() if colormap is not None and colormap.isEditable(): # can reset only in the case the colormap changed - rStateEnabled = colormap._toDict() != self._colormapStoredState + rStateEnabled = colormap != self._colormapStoredState resetButton.setEnabled(rStateEnabled) def _applyColormap(self): @@ -856,12 +983,8 @@ class ColormapDialog(qt.QDialog): self._maxValue.setEnabled(False) else: self._ignoreColormapChange = True - - if colormap.getName() is not None: - name = colormap.getName() - self._comboBoxColormap.setCurrentName(name) - self._comboBoxColormap.setEnabled(self._colormap().isEditable()) - + self._comboBoxColormap.setCurrentLut(colormap) + self._comboBoxColormap.setEnabled(colormap.isEditable()) assert colormap.getNormalization() in Colormap.NORMALIZATIONS self._normButtonLinear.setChecked( colormap.getNormalization() == Colormap.LINEAR) @@ -870,12 +993,17 @@ class ColormapDialog(qt.QDialog): vmin = colormap.getVMin() vmax = colormap.getVMax() dataRange = colormap.getColormapRange() - self._normButtonLinear.setEnabled(self._colormap().isEditable()) - self._normButtonLog.setEnabled(self._colormap().isEditable()) + self._normButtonLinear.setEnabled(colormap.isEditable()) + self._normButtonLog.setEnabled(colormap.isEditable()) self._minValue.setValue(vmin or dataRange[0], isAuto=vmin is None) self._maxValue.setValue(vmax or dataRange[1], isAuto=vmax is None) - self._minValue.setEnabled(self._colormap().isEditable()) - self._maxValue.setEnabled(self._colormap().isEditable()) + self._minValue.setEnabled(colormap.isEditable()) + self._maxValue.setEnabled(colormap.isEditable()) + + axis = self._plot.getXAxis() + scale = axis.LINEAR if colormap.getNormalization() == Colormap.LINEAR else axis.LOGARITHMIC + axis.setScale(scale) + self._ignoreColormapChange = False self._plotUpdate() @@ -908,26 +1036,47 @@ class ColormapDialog(qt.QDialog): self._plotUpdate() self._updateResetButton() - def _updateName(self): + def _updateLut(self): if self._ignoreColormapChange is True: return - if self._colormap(): + colormap = self._colormap() + if colormap is not None: self._ignoreColormapChange = True - self._colormap().setName( - self._comboBoxColormap.getCurrentName()) + name = self._comboBoxColormap.getCurrentName() + if name is not None: + colormap.setName(name) + else: + lut = self._comboBoxColormap.getCurrentColors() + colormap.setColormapLUT(lut) self._ignoreColormapChange = False - def _updateLinearNorm(self, isNormLinear): + def _updateNormalization(self, button): if self._ignoreColormapChange is True: return + if not button.isChecked(): + return + + if button is self._normButtonLinear: + norm = Colormap.LINEAR + scale = Axis.LINEAR + elif button is self._normButtonLog: + norm = Colormap.LOGARITHM + scale = Axis.LOGARITHMIC + else: + assert(False) - if self._colormap(): + colormap = self.getColormap() + if colormap is not None: self._ignoreColormapChange = True - norm = Colormap.LINEAR if isNormLinear else Colormap.LOGARITHM - self._colormap().setNormalization(norm) + colormap.setNormalization(norm) + axis = self._plot.getXAxis() + axis.setScale(scale) self._ignoreColormapChange = False + self._invalidateHistogram() + self._updateMinMaxData() + def _minMaxTextEdited(self, text): """Handle _minValue and _maxValue textEdited signal""" self._minMaxWasEdited = True @@ -975,13 +1124,3 @@ class ColormapDialog(qt.QDialog): else: # Use QDialog keyPressEvent super(ColormapDialog, self).keyPressEvent(event) - - def _activeLogNorm(self, isLog): - if self._ignoreColormapChange is True: - return - if self._colormap(): - self._ignoreColormapChange = True - norm = Colormap.LOGARITHM if isLog is True else Colormap.LINEAR - self._colormap().setNormalization(norm) - self._ignoreColormapChange = False - self._updateMinMaxData() diff --git a/silx/gui/dialog/DataFileDialog.py b/silx/gui/dialog/DataFileDialog.py index 7ff1258..d2d76a3 100644 --- a/silx/gui/dialog/DataFileDialog.py +++ b/silx/gui/dialog/DataFileDialog.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2016 European Synchrotron Radiation Facility +# Copyright (c) 2016-2018 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -30,16 +30,14 @@ __authors__ = ["V. Valls"] __license__ = "MIT" __date__ = "14/02/2018" +import enum import logging from silx.gui import qt from silx.gui.hdf5.Hdf5Formatter import Hdf5Formatter import silx.io from .AbstractDataFileDialog import AbstractDataFileDialog -from silx.third_party import enum -try: - import fabio -except ImportError: - fabio = None + +import fabio _logger = logging.getLogger(__name__) diff --git a/silx/gui/dialog/FileTypeComboBox.py b/silx/gui/dialog/FileTypeComboBox.py index 07b11cf..92529bc 100644 --- a/silx/gui/dialog/FileTypeComboBox.py +++ b/silx/gui/dialog/FileTypeComboBox.py @@ -28,12 +28,9 @@ This module contains utilitaries used by other dialog modules. __authors__ = ["V. Valls"] __license__ = "MIT" -__date__ = "06/02/2018" +__date__ = "17/01/2019" -try: - import fabio -except ImportError: - fabio = None +import fabio import silx.io from silx.gui import qt @@ -82,7 +79,7 @@ class FileTypeComboBox(qt.QComboBox): def __initItems(self): self.clear() - if fabio is not None and self.__fabioUrlSupported: + if self.__fabioUrlSupported: self.__insertFabioFormats() self.__insertSilxFormats() self.__insertAllSupported() @@ -138,21 +135,36 @@ class FileTypeComboBox(qt.QComboBox): def __insertFabioFormats(self): formats = fabio.fabioformats.get_classes(reader=True) + from fabio import fabioutils + if hasattr(fabioutils, "COMPRESSED_EXTENSIONS"): + compressedExtensions = fabioutils.COMPRESSED_EXTENSIONS + else: + # Support for fabio < 0.9 + compressedExtensions = set(["gz", "bz2"]) + extensions = [] allExtensions = set([]) + def extensionsIterator(reader): + for extension in reader.DEFAULT_EXTENSIONS: + yield "*.%s" % extension + for compressedExtension in compressedExtensions: + for extension in reader.DEFAULT_EXTENSIONS: + yield "*.%s.%s" % (extension, compressedExtension) + for reader in formats: if not hasattr(reader, "DESCRIPTION"): continue if not hasattr(reader, "DEFAULT_EXTENSIONS"): continue - ext = reader.DEFAULT_EXTENSIONS - ext = ["*.%s" % e for e in ext] + displayext = reader.DEFAULT_EXTENSIONS + displayext = ["*.%s" % e for e in displayext] + ext = list(extensionsIterator(reader)) allExtensions.update(ext) if ext == []: ext = ["*"] - extensions.append((reader.DESCRIPTION, ext, reader.codec_name())) + extensions.append((reader.DESCRIPTION, displayext, ext, reader.codec_name())) extensions = list(sorted(extensions)) allExtensions = list(sorted(list(allExtensions))) @@ -162,13 +174,14 @@ class FileTypeComboBox(qt.QComboBox): self.setItemData(index, Codec(any_fabio=True), role=self.CODEC_ROLE) for e in extensions: + description, displayExt, allExt, _codecName = e index = self.count() if len(e[1]) < 10: - self.addItem("%s%s (%s)" % (self.INDENTATION, e[0], " ".join(e[1]))) + self.addItem("%s%s (%s)" % (self.INDENTATION, description, " ".join(displayExt))) else: - self.addItem(e[0]) - codec = Codec(fabio_codec=e[2]) - self.setItemData(index, e[1], role=self.EXTENSIONS_ROLE) + self.addItem("%s%s" % (self.INDENTATION, description)) + codec = Codec(fabio_codec=_codecName) + self.setItemData(index, allExt, role=self.EXTENSIONS_ROLE) self.setItemData(index, codec, role=self.CODEC_ROLE) def itemExtensions(self, index): diff --git a/silx/gui/dialog/ImageFileDialog.py b/silx/gui/dialog/ImageFileDialog.py index c324071..ef6b472 100644 --- a/silx/gui/dialog/ImageFileDialog.py +++ b/silx/gui/dialog/ImageFileDialog.py @@ -36,10 +36,7 @@ from silx.gui import qt from silx.gui.plot.PlotWidget import PlotWidget from .AbstractDataFileDialog import AbstractDataFileDialog import silx.io -try: - import fabio -except ImportError: - fabio = None +import fabio _logger = logging.getLogger(__name__) diff --git a/silx/gui/dialog/SafeFileSystemModel.py b/silx/gui/dialog/SafeFileSystemModel.py index 198e089..26954e3 100644 --- a/silx/gui/dialog/SafeFileSystemModel.py +++ b/silx/gui/dialog/SafeFileSystemModel.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2016 European Synchrotron Radiation Facility +# Copyright (c) 2016-2018 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -34,8 +34,10 @@ import sys import os.path import logging import weakref + +import six + from silx.gui import qt -from silx.third_party import six from .SafeFileIconProvider import SafeFileIconProvider _logger = logging.getLogger(__name__) diff --git a/silx/gui/dialog/test/test_colormapdialog.py b/silx/gui/dialog/test/test_colormapdialog.py index 6e50193..cbc9de1 100644 --- a/silx/gui/dialog/test/test_colormapdialog.py +++ b/silx/gui/dialog/test/test_colormapdialog.py @@ -26,13 +26,11 @@ __authors__ = ["T. Vincent"] __license__ = "MIT" -__date__ = "23/05/2018" +__date__ = "09/11/2018" -import doctest import unittest -from silx.gui.utils.testutils import qWaitForWindowExposedAndActivate from silx.gui import qt from silx.gui.dialog import ColormapDialog from silx.gui.utils.testutils import TestCaseQt @@ -47,23 +45,6 @@ import numpy.random _qapp = qt.QApplication.instance() or qt.QApplication([]) -def _tearDownQt(docTest): - """Tear down to use for test from docstring. - - Checks that dialog widget is displayed - """ - dialogWidget = docTest.globs['dialog'] - qWaitForWindowExposedAndActivate(dialogWidget) - dialogWidget.setAttribute(qt.Qt.WA_DeleteOnClose) - dialogWidget.close() - del dialogWidget - _qapp.processEvents() - - -cmapDocTestSuite = doctest.DocTestSuite(ColormapDialog, tearDown=_tearDownQt) -"""Test suite of tests from the module's docstrings.""" - - class TestColormapDialog(TestCaseQt, ParametricTestCase): """Test the ColormapDialog.""" def setUp(self): @@ -86,10 +67,12 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase): editing the same colormap""" colormapDiag2 = ColormapDialog.ColormapDialog() colormapDiag2.setColormap(self.colormap) + colormapDiag2.show() self.colormapDiag.setColormap(self.colormap) + self.colormapDiag.show() - self.colormapDiag._comboBoxColormap.setCurrentName('red') - self.colormapDiag._normButtonLog.setChecked(True) + self.colormapDiag._comboBoxColormap._setCurrentName('red') + self.colormapDiag._normButtonLog.click() self.assertTrue(self.colormap.getName() == 'red') self.assertTrue(self.colormapDiag.getColormap().getName() == 'red') self.assertTrue(self.colormap.getNormalization() == 'log') @@ -178,6 +161,7 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase): def testSetColormapIsCorrect(self): """Make sure the interface fir the colormap when set a new colormap""" self.colormap.setName('red') + self.colormapDiag.show() for norm in (Colormap.NORMALIZATIONS): for autoscale in (True, False): if autoscale is True: @@ -211,7 +195,7 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase): self.colormapDiag.show() del self.colormap self.assertTrue(self.colormapDiag.getColormap() is None) - self.colormapDiag._comboBoxColormap.setCurrentName('blue') + self.colormapDiag._comboBoxColormap._setCurrentName('blue') def testColormapEditedOutside(self): """Make sure the GUI is still up to date if the colormap is modified @@ -274,7 +258,7 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase): cb = self.colormapDiag._comboBoxColormap self.assertTrue(cb.getCurrentName() == colormapName) cb.setCurrentIndex(0) - index = cb.findColormap(colormapName) + index = cb.findLutName(colormapName) assert index is not 0 # if 0 then the rest of the test has no sense cb.setCurrentIndex(index) self.assertTrue(cb.getCurrentName() == colormapName) @@ -283,6 +267,7 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase): """Test that the colormapDialog is correctly updated when changing the colormap editable status""" colormap = Colormap(normalization='linear', vmin=1.0, vmax=10.0) + self.colormapDiag.show() self.colormapDiag.setColormap(colormap) for editable in (True, False): with self.subTest(editable=editable): @@ -302,7 +287,7 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase): # False self.colormapDiag.setModal(False) colormap.setEditable(True) - self.colormapDiag._normButtonLog.setChecked(True) + self.colormapDiag._normButtonLog.click() resetButton = self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset) self.assertTrue(resetButton.isEnabled()) colormap.setEditable(False) @@ -387,7 +372,6 @@ class TestColormapAction(TestCaseQt): def suite(): test_suite = unittest.TestSuite() - test_suite.addTest(cmapDocTestSuite) for testClass in (TestColormapDialog, TestColormapAction): test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase( testClass)) diff --git a/silx/gui/dialog/test/test_datafiledialog.py b/silx/gui/dialog/test/test_datafiledialog.py index aff6bc4..06f8961 100644 --- a/silx/gui/dialog/test/test_datafiledialog.py +++ b/silx/gui/dialog/test/test_datafiledialog.py @@ -36,16 +36,8 @@ import shutil import os import io import weakref - -try: - import fabio -except ImportError: - fabio = None -try: - import h5py -except ImportError: - h5py = None - +import fabio +import h5py import silx.io.url from silx.gui import qt from silx.gui.utils import testutils @@ -62,36 +54,33 @@ def setUpModule(): data = numpy.arange(100 * 100) data.shape = 100, 100 - if fabio is not None: - filename = _tmpDirectory + "/singleimage.edf" - image = fabio.edfimage.EdfImage(data=data) - image.write(filename) - - if h5py is not None: - filename = _tmpDirectory + "/data.h5" - f = h5py.File(filename, "w") - f["scalar"] = 10 - f["image"] = data - f["cube"] = [data, data + 1, data + 2] - f["complex_image"] = data * 1j - f["group/image"] = data - f["nxdata/foo"] = 10 - f["nxdata"].attrs["NX_class"] = u"NXdata" - f.close() - - if h5py is not None: - directory = os.path.join(_tmpDirectory, "data") - os.mkdir(directory) - filename = os.path.join(directory, "data.h5") - f = h5py.File(filename, "w") - f["scalar"] = 10 - f["image"] = data - f["cube"] = [data, data + 1, data + 2] - f["complex_image"] = data * 1j - f["group/image"] = data - f["nxdata/foo"] = 10 - f["nxdata"].attrs["NX_class"] = u"NXdata" - f.close() + filename = _tmpDirectory + "/singleimage.edf" + image = fabio.edfimage.EdfImage(data=data) + image.write(filename) + + filename = _tmpDirectory + "/data.h5" + f = h5py.File(filename, "w") + f["scalar"] = 10 + f["image"] = data + f["cube"] = [data, data + 1, data + 2] + f["complex_image"] = data * 1j + f["group/image"] = data + f["nxdata/foo"] = 10 + f["nxdata"].attrs["NX_class"] = u"NXdata" + f.close() + + directory = os.path.join(_tmpDirectory, "data") + os.mkdir(directory) + filename = os.path.join(directory, "data.h5") + f = h5py.File(filename, "w") + f["scalar"] = 10 + f["image"] = data + f["cube"] = [data, data + 1, data + 2] + f["complex_image"] = data * 1j + f["group/image"] = data + f["nxdata/foo"] = 10 + f["nxdata"].attrs["NX_class"] = u"NXdata" + f.close() filename = _tmpDirectory + "/badformat.h5" with io.open(filename, "wb") as f: @@ -185,8 +174,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(dialog.result(), qt.QDialog.Rejected) def testSelectRoot_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -211,8 +198,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(dialog.result(), qt.QDialog.Accepted) def testSelectGroup_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -243,8 +228,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(dialog.result(), qt.QDialog.Accepted) def testSelectDataset_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -275,8 +258,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(dialog.result(), qt.QDialog.Accepted) def testClickOnBackToParentTool(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -307,8 +288,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(url.text(), _tmpDirectory) def testClickOnBackToRootTool(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -332,8 +311,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # self.assertFalse(button.isEnabled()) def testClickOnBackToDirectoryTool(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -361,8 +338,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.allowedLeakingWidgets = 1 def testClickOnHistoryTools(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -402,8 +377,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(url.text(), path3) def testSelectImageFromEdf(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -417,8 +390,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), url.path()) def testSelectImage(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -433,8 +404,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectScalar(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -449,8 +418,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectGroup(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -467,8 +434,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(uri.data_path(), "/group") def testSelectRoot(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -485,8 +450,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(uri.data_path(), "/") def testSelectH5_Activate(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -533,10 +496,6 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): return selectable def testFilterExtensions(self): - if h5py is None: - self.skipTest("h5py is missing") - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -558,8 +517,6 @@ class TestDataFileDialog_FilterDataset(testutils.TestCaseQt, _UtilsMixin): return dialog def testSelectGroup_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -585,8 +542,6 @@ class TestDataFileDialog_FilterDataset(testutils.TestCaseQt, _UtilsMixin): self.assertFalse(button.isEnabled()) def testSelectDataset_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -632,8 +587,6 @@ class TestDataFileDialog_FilterGroup(testutils.TestCaseQt, _UtilsMixin): return dialog def testSelectGroup_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -666,8 +619,6 @@ class TestDataFileDialog_FilterGroup(testutils.TestCaseQt, _UtilsMixin): self.assertRaises(Exception, dialog.selectedData) def testSelectDataset_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -711,8 +662,6 @@ class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): return dialog def testSelectGroupRefused_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -740,8 +689,6 @@ class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): self.assertRaises(Exception, dialog.selectedData) def testSelectNXdataAccepted_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() @@ -944,8 +891,6 @@ class TestDataFileDialogApi(testutils.TestCaseQt, _UtilsMixin): self.assertIsNone(dialog._selectedData()) def testBadSubpath(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() self.qWaitForPendingActions(dialog) @@ -965,8 +910,6 @@ class TestDataFileDialogApi(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(url.data_path(), "/group") def testUnsupportedSlicingPath(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() self.qWaitForPendingActions(dialog) dialog.selectUrl(_tmpDirectory + "/data.h5?path=/cube&slice=0") diff --git a/silx/gui/dialog/test/test_imagefiledialog.py b/silx/gui/dialog/test/test_imagefiledialog.py index 66469f3..068dcb9 100644 --- a/silx/gui/dialog/test/test_imagefiledialog.py +++ b/silx/gui/dialog/test/test_imagefiledialog.py @@ -36,16 +36,8 @@ import shutil import os import io import weakref - -try: - import fabio -except ImportError: - fabio = None -try: - import h5py -except ImportError: - h5py = None - +import fabio +import h5py import silx.io.url from silx.gui import qt from silx.gui.utils import testutils @@ -63,42 +55,39 @@ def setUpModule(): data = numpy.arange(100 * 100) data.shape = 100, 100 - if fabio is not None: - filename = _tmpDirectory + "/singleimage.edf" - image = fabio.edfimage.EdfImage(data=data) - image.write(filename) - - filename = _tmpDirectory + "/multiframe.edf" - image = fabio.edfimage.EdfImage(data=data) - image.appendFrame(data=data + 1) - image.appendFrame(data=data + 2) - image.write(filename) - - filename = _tmpDirectory + "/singleimage.msk" - image = fabio.fit2dmaskimage.Fit2dMaskImage(data=data % 2 == 1) - image.write(filename) - - if h5py is not None: - filename = _tmpDirectory + "/data.h5" - f = h5py.File(filename, "w") - f["scalar"] = 10 - f["image"] = data - f["cube"] = [data, data + 1, data + 2] - f["complex_image"] = data * 1j - f["group/image"] = data - f.close() - - if h5py is not None: - directory = os.path.join(_tmpDirectory, "data") - os.mkdir(directory) - filename = os.path.join(directory, "data.h5") - f = h5py.File(filename, "w") - f["scalar"] = 10 - f["image"] = data - f["cube"] = [data, data + 1, data + 2] - f["complex_image"] = data * 1j - f["group/image"] = data - f.close() + filename = _tmpDirectory + "/singleimage.edf" + image = fabio.edfimage.EdfImage(data=data) + image.write(filename) + + filename = _tmpDirectory + "/multiframe.edf" + image = fabio.edfimage.EdfImage(data=data) + image.appendFrame(data=data + 1) + image.appendFrame(data=data + 2) + image.write(filename) + + filename = _tmpDirectory + "/singleimage.msk" + image = fabio.fit2dmaskimage.Fit2dMaskImage(data=data % 2 == 1) + image.write(filename) + + filename = _tmpDirectory + "/data.h5" + f = h5py.File(filename, "w") + f["scalar"] = 10 + f["image"] = data + f["cube"] = [data, data + 1, data + 2] + f["complex_image"] = data * 1j + f["group/image"] = data + f.close() + + directory = os.path.join(_tmpDirectory, "data") + os.mkdir(directory) + filename = os.path.join(directory, "data.h5") + f = h5py.File(filename, "w") + f["scalar"] = 10 + f["image"] = data + f["cube"] = [data, data + 1, data + 2] + f["complex_image"] = data * 1j + f["group/image"] = data + f.close() filename = _tmpDirectory + "/badformat.edf" with io.open(filename, "wb") as f: @@ -192,8 +181,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(dialog.result(), qt.QDialog.Rejected) def testDisplayAndClickOpen(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -259,8 +246,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(dialog.viewMode(), qt.QFileDialog.List) def testClickOnBackToParentTool(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -291,8 +276,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(url.text(), _tmpDirectory) def testClickOnBackToRootTool(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -316,8 +299,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # self.assertFalse(button.isEnabled()) def testClickOnBackToDirectoryTool(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -345,8 +326,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.allowedLeakingWidgets = 1 def testClickOnHistoryTools(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -386,8 +365,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(url.text(), path3) def testSelectImageFromEdf(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -402,8 +379,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectImageFromEdf_Activate(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -426,8 +401,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectFrameFromEdf(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -444,8 +417,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectImageFromMsk(self): - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -460,8 +431,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectImageFromH5(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -476,8 +445,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectH5_Activate(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -498,8 +465,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.selectedUrl(), path) def testSelectFrameFromH5(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -541,10 +506,6 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): return selectable def testFilterExtensions(self): - if h5py is None: - self.skipTest("h5py is missing") - if fabio is None: - self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] filters = testutils.findChildren(dialog, qt.QWidget, name="fileTypeCombo")[0] @@ -745,16 +706,12 @@ class TestImageFileDialogApi(testutils.TestCaseQt, _UtilsMixin): self.assertSamePath(dialog.directory(), _tmpDirectory) def testBadDataType(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.selectUrl(_tmpDirectory + "/data.h5::/complex_image") self.qWaitForPendingActions(dialog) self.assertIsNone(dialog._selectedData()) def testBadDataShape(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() dialog.selectUrl(_tmpDirectory + "/data.h5::/unknown") self.qWaitForPendingActions(dialog) @@ -773,8 +730,6 @@ class TestImageFileDialogApi(testutils.TestCaseQt, _UtilsMixin): self.assertIsNone(dialog._selectedData()) def testBadSubpath(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() self.qWaitForPendingActions(dialog) @@ -794,8 +749,6 @@ class TestImageFileDialogApi(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(url.data_path(), "/group") def testBadSlicingPath(self): - if h5py is None: - self.skipTest("h5py is missing") dialog = self.createDialog() self.qWaitForPendingActions(dialog) dialog.selectUrl(_tmpDirectory + "/data.h5::/cube[a;45,-90]") diff --git a/silx/gui/dialog/utils.py b/silx/gui/dialog/utils.py index 1c16b44..e2334f9 100644 --- a/silx/gui/dialog/utils.py +++ b/silx/gui/dialog/utils.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2016 European Synchrotron Radiation Facility +# Copyright (c) 2016-2018 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -33,8 +33,10 @@ __date__ = "25/10/2017" import os import sys import types + +import six + from silx.gui import qt -from silx.third_party import six def samefile(path1, path2): -- cgit v1.2.3