diff options
Diffstat (limited to 'src/silx/gui/dialog')
-rw-r--r-- | src/silx/gui/dialog/AbstractDataFileDialog.py | 165 | ||||
-rw-r--r-- | src/silx/gui/dialog/ColormapDialog.py | 358 | ||||
-rw-r--r-- | src/silx/gui/dialog/DataFileDialog.py | 4 | ||||
-rw-r--r-- | src/silx/gui/dialog/DatasetDialog.py | 27 | ||||
-rw-r--r-- | src/silx/gui/dialog/FileTypeComboBox.py | 24 | ||||
-rw-r--r-- | src/silx/gui/dialog/GroupDialog.py | 33 | ||||
-rw-r--r-- | src/silx/gui/dialog/ImageFileDialog.py | 10 | ||||
-rw-r--r-- | src/silx/gui/dialog/SafeFileIconProvider.py | 1 | ||||
-rw-r--r-- | src/silx/gui/dialog/SafeFileSystemModel.py | 25 | ||||
-rw-r--r-- | src/silx/gui/dialog/test/test_colormapdialog.py | 704 | ||||
-rw-r--r-- | src/silx/gui/dialog/test/test_datafiledialog.py | 203 | ||||
-rw-r--r-- | src/silx/gui/dialog/test/test_imagefiledialog.py | 172 | ||||
-rw-r--r-- | src/silx/gui/dialog/utils.py | 2 |
13 files changed, 977 insertions, 751 deletions
diff --git a/src/silx/gui/dialog/AbstractDataFileDialog.py b/src/silx/gui/dialog/AbstractDataFileDialog.py index f656bb2..00db275 100644 --- a/src/silx/gui/dialog/AbstractDataFileDialog.py +++ b/src/silx/gui/dialog/AbstractDataFileDialog.py @@ -56,7 +56,6 @@ some version of PyQt.""" class _IconProvider(object): - FileDialogToParentDir = qt.QStyle.SP_CustomBase + 1 FileDialogToParentFile = qt.QStyle.SP_CustomBase + 2 @@ -92,7 +91,9 @@ class _IconProvider(object): pixmap.fill(qt.Qt.transparent) painter = qt.QPainter(pixmap) painter.drawPixmap(0, 0, backgroundIcon.pixmap(baseSize, mode=mode)) - painter.drawPixmap(0, size.height() // 3, baseIcon.pixmap(baseSize, mode=mode)) + painter.drawPixmap( + 0, size.height() // 3, baseIcon.pixmap(baseSize, mode=mode) + ) painter.end() icon.addPixmap(pixmap, mode=mode) @@ -100,12 +101,16 @@ class _IconProvider(object): def getFileDialogToParentDir(self): if self.__iconFileDialogToParentDir is None: - self.__iconFileDialogToParentDir = self._createIconToParent(qt.QStyle.SP_DirIcon) + self.__iconFileDialogToParentDir = self._createIconToParent( + qt.QStyle.SP_DirIcon + ) return self.__iconFileDialogToParentDir def getFileDialogToParentFile(self): if self.__iconFileDialogToParentFile is None: - self.__iconFileDialogToParentFile = self._createIconToParent(qt.QStyle.SP_FileIcon) + self.__iconFileDialogToParentFile = self._createIconToParent( + qt.QStyle.SP_FileIcon + ) return self.__iconFileDialogToParentFile def icon(self, kind): @@ -147,13 +152,17 @@ class _SideBar(qt.QListView): :rtype: List[str] """ urls = [] - version = tuple(map(int, qt.qVersion().split('.')[:3])) + version = tuple(map(int, qt.qVersion().split(".")[:3])) feed_sidebar = True if not DEFAULT_SIDEBAR_URL: _logger.debug("Skip default sidebar URLs (from setted variable)") feed_sidebar = False - elif version < (5, 11, 2) and qt.BINDING == "PyQt5" and sys.platform in ["linux", "linux2"]: + elif ( + version < (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)") feed_sidebar = False @@ -186,7 +195,9 @@ class _SideBar(qt.QListView): selectionModel = self.selectionModel() if selected is not None: - selectionModel.setCurrentIndex(selected, qt.QItemSelectionModel.ClearAndSelect) + selectionModel.setCurrentIndex( + selected, qt.QItemSelectionModel.ClearAndSelect + ) else: selectionModel.clear() @@ -232,11 +243,12 @@ class _SideBar(qt.QListView): def sizeHint(self): index = self.model().index(0, 0) - return self.sizeHintForIndex(index) + qt.QSize(2 * self.frameWidth(), 2 * self.frameWidth()) + return self.sizeHintForIndex(index) + qt.QSize( + 2 * self.frameWidth(), 2 * self.frameWidth() + ) class _Browser(qt.QStackedWidget): - activated = qt.Signal(qt.QModelIndex) selected = qt.Signal(qt.QModelIndex) rootIndexChanged = qt.Signal(qt.QModelIndex) @@ -302,7 +314,7 @@ class _Browser(qt.QStackedWidget): elif self.currentIndex() == 1: return qt.QFileDialog.Detail else: - assert(False) + assert False def setViewMode(self, mode): """Set the current view mode. @@ -314,7 +326,7 @@ class _Browser(qt.QStackedWidget): elif mode == qt.QFileDialog.List: self.showList() else: - assert(False) + assert False def showList(self): self.__listView.show() @@ -342,11 +354,10 @@ class _Browser(qt.QStackedWidget): self.__detailView.setModel(None) def setRootIndex(self, index, model=None): - """Sets the root item to the item at the given index. - """ + """Sets the root item to the item at the given index.""" rootIndex = self.__listView.rootIndex() newModel = model or index.model() - assert(newModel is not None) + assert newModel is not None if rootIndex is None or rootIndex.model() is not newModel: # update the model @@ -415,12 +426,16 @@ class _Browser(qt.QStackedWidget): nameId = stream.readQString() if nameId != "Browser": - _logger.warning("Stored state contains an invalid name id. Browser restoration cancelled.") + _logger.warning( + "Stored state contains an invalid name id. Browser restoration cancelled." + ) return False version = stream.readInt32() if version != self.__serialVersion: - _logger.warning("Stored state contains an invalid version. Browser restoration cancelled.") + _logger.warning( + "Stored state contains an invalid version. Browser restoration cancelled." + ) return False headerData = stream.readQVariant() @@ -438,12 +453,12 @@ class _Browser(qt.QStackedWidget): data = qt.QByteArray() stream = qt.QDataStream(data, qt.QIODevice.WriteOnly) - nameId = u"Browser" + nameId = "Browser" stream.writeQString(nameId) stream.writeInt32(self.__serialVersion) stream.writeQVariant(self.__detailView.header().saveState()) viewMode = self.viewMode() - if qt.BINDING == 'PyQt6': # No auto conversion to int + if qt.BINDING in ("PyQt6", "PySide6"): # No auto conversion to int viewMode = viewMode.value stream.writeInt32(viewMode) @@ -451,7 +466,6 @@ class _Browser(qt.QStackedWidget): class _FabioData(object): - def __init__(self, fabioFile): self.__fabioFile = fabioFile @@ -492,7 +506,6 @@ class _PathEdit(qt.QLineEdit): class _CatchResizeEvent(qt.QObject): - resized = qt.Signal(qt.QResizeEvent) def __init__(self, parent, target): @@ -565,6 +578,7 @@ class AbstractDataFileDialog(qt.QDialog): _logger.debug("Uses default QFileSystemModel with a SafeFileIconProvider") self.__fileModel = qt.QFileSystemModel(self) from .SafeFileIconProvider import SafeFileIconProvider + iconProvider = SafeFileIconProvider() self.__fileModel.setIconProvider(iconProvider) @@ -677,8 +691,12 @@ class AbstractDataFileDialog(qt.QDialog): self.__fileTypeCombo = FileTypeComboBox(self) self.__fileTypeCombo.setObjectName("fileTypeCombo") self.__fileTypeCombo.setDuplicatesEnabled(False) - self.__fileTypeCombo.setSizeAdjustPolicy(qt.QComboBox.AdjustToMinimumContentsLengthWithIcon) - self.__fileTypeCombo.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed) + self.__fileTypeCombo.setSizeAdjustPolicy( + qt.QComboBox.AdjustToMinimumContentsLengthWithIcon + ) + self.__fileTypeCombo.setSizePolicy( + qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed + ) self.__fileTypeCombo.activated[int].connect(self.__filterSelected) self.__fileTypeCombo.setFabioUrlSupproted(self._isFabioFilesSupported()) @@ -708,7 +726,9 @@ class AbstractDataFileDialog(qt.QDialog): if self.__selectorWidget is not None: self.__selectorWidget.selectionChanged.connect(self.__selectorWidgetChanged) - self.__previewToolBar = self._createPreviewToolbar(self, self.__previewWidget, self.__selectorWidget) + self.__previewToolBar = self._createPreviewToolbar( + self, self.__previewWidget, self.__selectorWidget + ) self.__dataIcon = qt.QLabel(self) self.__dataIcon.setSizePolicy(qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed) @@ -767,7 +787,9 @@ class AbstractDataFileDialog(qt.QDialog): parentFileDirectory = qt.QAction(toolbar) parentFileDirectory.setText("Parent directory of the file") parentFileDirectory.setObjectName("toDirectoryAction") - parentFileDirectory.setIcon(iconProvider.icon(iconProvider.FileDialogToParentDir)) + parentFileDirectory.setIcon( + iconProvider.icon(iconProvider.FileDialogToParentDir) + ) parentFileDirectory.triggered.connect(self.__navigateToParentDir) self.__parentFileDirectoryAction = parentFileDirectory @@ -818,11 +840,15 @@ class AbstractDataFileDialog(qt.QDialog): dummyCombo.setFixedHeight(self.__fileTypeCombo.height()) self.__resizeCombo = _CatchResizeEvent(self, self.__fileTypeCombo) - self.__resizeCombo.resized.connect(lambda e: dummyCombo.setFixedHeight(e.size().height())) + self.__resizeCombo.resized.connect( + lambda e: dummyCombo.setFixedHeight(e.size().height()) + ) dummyToolBar.setFixedHeight(self.__browseToolBar.height()) self.__resizeToolbar = _CatchResizeEvent(self, self.__browseToolBar) - self.__resizeToolbar.resized.connect(lambda e: dummyToolBar.setFixedHeight(e.size().height())) + self.__resizeToolbar.resized.connect( + lambda e: dummyToolBar.setFixedHeight(e.size().height()) + ) datasetSelection = qt.QWidget(self) layoutLeft = qt.QVBoxLayout() @@ -831,7 +857,9 @@ class AbstractDataFileDialog(qt.QDialog): layoutLeft.addWidget(self.__browser) layoutLeft.addWidget(self.__fileTypeCombo) datasetSelection.setLayout(layoutLeft) - datasetSelection.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Expanding) + datasetSelection.setSizePolicy( + qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Expanding + ) infoLayout = qt.QHBoxLayout() infoLayout.setContentsMargins(0, 0, 0, 0) @@ -858,7 +886,9 @@ class AbstractDataFileDialog(qt.QDialog): dummyToolbar2.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed) dummyToolbar2.setFixedHeight(self.__browseToolBar.height()) self.__resizeToolbar = _CatchResizeEvent(self, self.__browseToolBar) - self.__resizeToolbar.resized.connect(lambda e: dummyToolbar2.setFixedHeight(e.size().height())) + self.__resizeToolbar.resized.connect( + lambda e: dummyToolbar2.setFixedHeight(e.size().height()) + ) dataLayout.addWidget(dummyToolbar2) dataLayout.addWidget(dataFrame) @@ -870,7 +900,9 @@ class AbstractDataFileDialog(qt.QDialog): dummyCombo2.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Fixed) dummyCombo2.setFixedHeight(self.__fileTypeCombo.height()) self.__resizeToolbar = _CatchResizeEvent(self, self.__fileTypeCombo) - self.__resizeToolbar.resized.connect(lambda e: dummyCombo2.setFixedHeight(e.size().height())) + self.__resizeToolbar.resized.connect( + lambda e: dummyCombo2.setFixedHeight(e.size().height()) + ) dataLayout.addWidget(dummyCombo2) dataSelection.setLayout(dataLayout) @@ -904,7 +936,10 @@ class AbstractDataFileDialog(qt.QDialog): def __navigateForward(self): """Navigate through the history one step forward.""" - if len(self.__currentHistory) > 0 and self.__currentHistoryLocation < len(self.__currentHistory) - 1: + if ( + len(self.__currentHistory) > 0 + and self.__currentHistoryLocation < len(self.__currentHistory) - 1 + ): self.__currentHistoryLocation += 1 url = self.__currentHistory[self.__currentHistoryLocation] self.selectUrl(url) @@ -971,7 +1006,7 @@ class AbstractDataFileDialog(qt.QDialog): self.__listViewAction.setChecked(True) self.__detailViewAction.setChecked(False) else: - assert(False) + assert False def __showAsListView(self): self.setViewMode(qt.QFileDialog.List) @@ -1005,7 +1040,7 @@ class AbstractDataFileDialog(qt.QDialog): if silx.io.is_group(obj): self.__browser.setRootIndex(index) else: - assert(False) + assert False def __browsedItemSelected(self, index): self.__dataSelected(index) @@ -1020,7 +1055,7 @@ class AbstractDataFileDialog(qt.QDialog): :param str path: Path to load """ - assert(path is not None) + assert path is not None if path != "" and not os.path.exists(path): return if self.hasPendingEvents(): @@ -1102,8 +1137,7 @@ class AbstractDataFileDialog(qt.QDialog): return True def __isSilxHavePriority(self, filename): - """Silx have priority when there is a specific decoder - """ + """Silx have priority when there is a specific decoder""" _, ext = os.path.splitext(filename) ext = "*%s" % ext formats = silx.io.supported_extensions(flat_formats=False) @@ -1166,14 +1200,17 @@ class AbstractDataFileDialog(qt.QDialog): if os.path.isfile(path): codec = self.__fileTypeCombo.currentCodec() is_fabio_decoder = codec.is_fabio_codec() - is_fabio_have_priority = not codec.is_silx_codec() and not self.__isSilxHavePriority(path) + 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 self.__openFabioFile(path) if self.__fabio is not None: selectedData = _FabioData(self.__fabio) else: - assert(False) + assert False self.__setData(selectedData) @@ -1193,7 +1230,9 @@ class AbstractDataFileDialog(qt.QDialog): self.__setSelectedData(data) self.__selectorWidget.hide() else: - self.__selectorWidget.setVisible(self.__selectorWidget.hasVisibleSelectors()) + self.__selectorWidget.setVisible( + self.__selectorWidget.hasVisibleSelectors() + ) # Needed to fake the fact we have to reset the zoom in preview self.__selectedData = None self.__selectorWidget.selectionChanged.emit() @@ -1266,7 +1305,10 @@ class AbstractDataFileDialog(qt.QDialog): def __updateDataInfo(self): if self.__errorWhileLoadingFile is not None: filename, message = self.__errorWhileLoadingFile - message = "<b>Error while loading file '%s'</b><hr/>%s" % (filename, message) + message = "<b>Error while loading file '%s'</b><hr/>%s" % ( + filename, + message, + ) size = self.__dataInfo.height() icon = self.style().standardIcon(qt.QStyle.SP_MessageBoxCritical) pixmap = icon.pixmap(size, size) @@ -1317,7 +1359,11 @@ class AbstractDataFileDialog(qt.QDialog): filename = "" dataPath = None - if useSelectorWidget and self.__selectorWidget is not None and self.__selectorWidget.isUsed(): + if ( + useSelectorWidget + and self.__selectorWidget is not None + and self.__selectorWidget.isUsed() + ): slicing = self.__selectorWidget.slicing() if slicing == tuple(): slicing = None @@ -1340,7 +1386,9 @@ class AbstractDataFileDialog(qt.QDialog): else: scheme = None - url = silx.io.url.DataUrl(file_path=filename, data_path=dataPath, data_slice=slicing, scheme=scheme) + url = silx.io.url.DataUrl( + file_path=filename, data_path=dataPath, data_slice=slicing, scheme=scheme + ) return url def __updatePath(self): @@ -1362,7 +1410,9 @@ class AbstractDataFileDialog(qt.QDialog): if currentUrl is None or currentUrl != url.path(): # clean up the forward history - self.__currentHistory = self.__currentHistory[0:self.__currentHistoryLocation + 1] + self.__currentHistory = self.__currentHistory[ + 0 : self.__currentHistoryLocation + 1 + ] self.__currentHistory.append(url.path()) self.__currentHistoryLocation += 1 @@ -1400,15 +1450,16 @@ class AbstractDataFileDialog(qt.QDialog): selectionModel.selectionChanged.connect(self.__shortcutSelected) def __updateActionHistory(self): - self.__forwardAction.setEnabled(len(self.__currentHistory) - 1 > self.__currentHistoryLocation) + self.__forwardAction.setEnabled( + len(self.__currentHistory) - 1 > self.__currentHistoryLocation + ) self.__backwardAction.setEnabled(self.__currentHistoryLocation > 0) def __textChanged(self, text): self.__pathChanged() def _isFabioFilesSupported(self): - """Returns true fabio files can be loaded. - """ + """Returns true fabio files can be loaded.""" return True def _isLoadableUrl(self, url): @@ -1479,7 +1530,7 @@ class AbstractDataFileDialog(qt.QDialog): # data = _FabioData(self.__fabio) # self.__setData(data) else: - assert(False) + assert False else: self.__browser.setRootIndex(index, model=self.__fileModel) self.__clearData() @@ -1615,7 +1666,7 @@ class AbstractDataFileDialog(qt.QDialog): """ if len(self.__currentHistory) <= 1: return [] - history = self.__currentHistory[0:self.__currentHistoryLocation] + history = self.__currentHistory[0 : self.__currentHistoryLocation] return list(history) def setHistory(self, history): @@ -1670,12 +1721,18 @@ class AbstractDataFileDialog(qt.QDialog): qualifiedName = stream.readQString() if qualifiedName != self.qualifiedName(): - _logger.warning("Stored state contains an invalid qualified name. %s restoration cancelled.", self.__class__.__name__) + _logger.warning( + "Stored state contains an invalid qualified name. %s restoration cancelled.", + self.__class__.__name__, + ) return False version = stream.readInt32() if version != self.__serialVersion: - _logger.warning("Stored state contains an invalid version. %s restoration cancelled.", self.__class__.__name__) + _logger.warning( + "Stored state contains an invalid version. %s restoration cancelled.", + self.__class__.__name__, + ) return False result = True @@ -1713,17 +1770,17 @@ class AbstractDataFileDialog(qt.QDialog): stream = qt.QDataStream(data, qt.QIODevice.WriteOnly) s = self.qualifiedName() - stream.writeQString(u"%s" % s) + stream.writeQString("%s" % s) stream.writeInt32(self.__serialVersion) stream.writeQVariant(self.__splitter.saveState()) - strings = [u"%s" % s.toString() for s in self.sidebarUrls()] + strings = ["%s" % s.toString() for s in self.sidebarUrls()] stream.writeQStringList(strings) - strings = [u"%s" % s for s in self.history()] + strings = ["%s" % s for s in self.history()] stream.writeQStringList(strings) - stream.writeQString(u"%s" % self.directory()) + stream.writeQString("%s" % self.directory()) stream.writeQVariant(self.__browser.saveState()) viewMode = self.viewMode() - if qt.BINDING == 'PyQt6': # No auto conversion to int + if qt.BINDING in ("PyQt6", "PySide6"): # No auto conversion to int viewMode = viewMode.value stream.writeInt32(viewMode) colormap = self.colormap() diff --git a/src/silx/gui/dialog/ColormapDialog.py b/src/silx/gui/dialog/ColormapDialog.py index f3f38b5..75ab39e 100644 --- a/src/silx/gui/dialog/ColormapDialog.py +++ b/src/silx/gui/dialog/ColormapDialog.py @@ -1,6 +1,6 @@ # /*########################################################################## # -# Copyright (c) 2004-2022 European Synchrotron Radiation Facility +# Copyright (c) 2004-2023 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 @@ -58,6 +58,8 @@ The updates of the colormap description are also available through the signal: :attr:`ColormapDialog.sigColormapChanged`. """ # noqa +from __future__ import annotations + __authors__ = ["V.A. Sole", "T. Vincent", "H. Payno"] __license__ = "MIT" __date__ = "08/12/2020" @@ -82,9 +84,9 @@ from silx.gui.qt import inspect as qtinspect from silx.gui.widgets.ColormapNameComboBox import ColormapNameComboBox from silx.gui.widgets.FormGridLayout import FormGridLayout from silx.math.histogram import Histogramnd -from silx.utils import deprecation from silx.gui.plot.items.roi import RectangleROI from silx.gui.plot.tools.roi import RegionOfInterestManager +from silx.utils.enum import Enum as _Enum _logger = logging.getLogger(__name__) @@ -128,8 +130,8 @@ class _BoundaryWidget(qt.QWidget): self.layout().setContentsMargins(0, 0, 0, 0) self._numVal = FloatEdit(parent=self, value=value) - self._iconAuto = icons.getQIcon('scale-auto') - self._iconFixed = icons.getQIcon('scale-fixed') + self._iconAuto = icons.getQIcon("scale-auto") + self._iconFixed = icons.getQIcon("scale-fixed") self._autoToggleAction = qt.QAction(self) self._autoToggleAction.setText("Auto scale") @@ -142,7 +144,7 @@ class _BoundaryWidget(qt.QWidget): self._numVal.addAction(self._autoToggleAction, qt.QLineEdit.LeadingPosition) self.layout().addWidget(self._numVal) - self._autoCB = qt.QCheckBox('auto', parent=self) + self._autoCB = qt.QCheckBox("auto", parent=self) self.layout().addWidget(self._autoCB) self._autoCB.setChecked(False) self._autoCB.setVisible(False) @@ -220,7 +222,7 @@ class _BoundaryWidget(qt.QWidget): color = palette.color(qt.QPalette.Disabled, qt.QPalette.Base) icon = self._iconAuto else: - color = palette.color(qt.QPalette.Normal, qt.QPalette.Base) + color = palette.color(qt.QPalette.Active, qt.QPalette.Base) icon = self._iconFixed palette.setColor(qt.QPalette.Base, color) self._numVal.setPalette(palette) @@ -228,7 +230,6 @@ class _BoundaryWidget(qt.QWidget): class _AutoscaleModeComboBox(qt.QComboBox): - DATA = { Colormap.MINMAX: ("Min/max", "Use the data min/max"), Colormap.STDDEV3: ("Mean±3std", "Use the data mean ± 3 × standard deviation"), @@ -275,7 +276,6 @@ class _AutoscaleModeComboBox(qt.QComboBox): class _AutoScaleButton(qt.QPushButton): - autoRangeChanged = qt.Signal(object) def __init__(self, parent=None): @@ -300,11 +300,13 @@ class _AutoScaleButton(qt.QPushButton): with utils.blockSignals(self): self.setChecked(autoRange[0] if autoRange[0] == autoRange[1] else False) + @enum.unique -class _DataInPlotMode(enum.Enum): +class DisplayMode(_Enum): """Enum for each mode of display of the data in the plot.""" - RANGE = 'range' - HISTOGRAM = 'histogram' + + RANGE = "range" + HISTOGRAM = "histogram" class _ColormapHistogram(qt.QWidget): @@ -333,7 +335,7 @@ class _ColormapHistogram(qt.QWidget): def __init__(self, parent): qt.QWidget.__init__(self, parent=parent) - self._dataInPlotMode = _DataInPlotMode.RANGE + self._displayMode = DisplayMode.RANGE self._finiteRange = None, None self._initPlot() @@ -350,7 +352,7 @@ class _ColormapHistogram(qt.QWidget): def paintEvent(self, event): if self._invalidated: - self._updateDataInPlot() + self._updateDisplayMode() self._invalidated = False self._updateMarkerPosition() return super(_ColormapHistogram, self).paintEvent(event) @@ -419,7 +421,9 @@ class _ColormapHistogram(qt.QWidget): dataRange = self._getNormalizedDataRange() if dataRange[0] is None or dataRange[1] is None: return None, None - counts, edges = self.parent().computeHistogram(data, scale=norm, dataRange=dataRange) + counts, edges = self.parent().computeHistogram( + data, scale=norm, dataRange=dataRange + ) return counts, edges def _getNormalizedDataRange(self): @@ -511,22 +515,22 @@ class _ColormapHistogram(qt.QWidget): self._plot.setDataMargins(0.125, 0.125, 0.01, 0.01) self._plot.getXAxis().setLabel("Data Values") self._plot.getYAxis().setLabel("") - self._plot.setInteractiveMode('select', zoomOnWheel=False) + self._plot.setInteractiveMode("select", zoomOnWheel=False) self._plot.setActiveCurveHandling(False) self._plot.setMinimumSize(qt.QSize(250, 200)) self._plot.sigPlotSignal.connect(self._plotEventReceived) palette = self.palette() - color = palette.color(qt.QPalette.Normal, qt.QPalette.Window) + color = palette.color(qt.QPalette.Active, qt.QPalette.Window) self._plot.setBackgroundColor(color) self._plot.setDataBackgroundColor("white") lut = numpy.arange(256) lut.shape = 1, -1 - self._plot.addImage(lut, legend='lut') + self._plot.addImage(lut, legend="lut") self._lutItem = self._plot._getItem("image", "lut") self._lutItem.setVisible(False) - self._plot.addScatter(x=[], y=[], value=[], legend='lut2') + self._plot.addScatter(x=[], y=[], value=[], legend="lut2") self._lutItem2 = self._plot._getItem("scatter", "lut2") self._lutItem2.setVisible(False) self.__lutY = numpy.array([-0.05] * 256) @@ -546,24 +550,32 @@ class _ColormapHistogram(qt.QWidget): group = qt.QActionGroup(self._plotToolbar) group.setExclusive(True) - + # data range mode action = qt.QAction("Data range", self) - action.setToolTip("Display the data range within the colormap range. A fast data processing have to be done.") - action.setIcon(icons.getQIcon('colormap-range')) + action.setToolTip( + "Display the data range within the colormap range. A fast data processing have to be done." + ) + action.setIcon(icons.getQIcon("colormap-range")) action.setCheckable(True) - action.setData(_DataInPlotMode.RANGE) - action.setChecked(action.data() == self._dataInPlotMode) + action.setData(DisplayMode.RANGE) + action.setChecked(action.data() == self._displayMode) self._plotToolbar.addAction(action) group.addAction(action) + self._dataRangeAction = action + # histogram mode action = qt.QAction("Histogram", self) - action.setToolTip("Display the data histogram within the colormap range. A slow data processing have to be done. ") - action.setIcon(icons.getQIcon('colormap-histogram')) + action.setToolTip( + "Display the data histogram within the colormap range. A slow data processing have to be done. " + ) + action.setIcon(icons.getQIcon("colormap-histogram")) action.setCheckable(True) - action.setData(_DataInPlotMode.HISTOGRAM) - action.setChecked(action.data() == self._dataInPlotMode) + action.setData(DisplayMode.HISTOGRAM) + action.setChecked(action.data() == self._displayMode) self._plotToolbar.addAction(action) group.addAction(action) - group.triggered.connect(self._displayDataInPlotModeChanged) + self._dataHistogramAction = action + group.setExclusive(True) + group.triggered.connect(self._displayModeChanged) plotBoxLayout = qt.QHBoxLayout() plotBoxLayout.setContentsMargins(0, 0, 0, 0) @@ -575,28 +587,28 @@ class _ColormapHistogram(qt.QWidget): def _plotEventReceived(self, event): """Handle events from the plot""" - kind = event['event'] + kind = event["event"] - if kind == 'markerMoving': - value = event['xdata'] - if event['label'] == 'Min': + if kind == "markerMoving": + value = event["xdata"] + if event["label"] == "Min": self._dragging = True, False, False self._finiteRange = value, self._finiteRange[1] self._last = value, None, None self._updateGammaPosition() self.sigRangeMoving.emit(*self._last) - elif event['label'] == 'Max': + elif event["label"] == "Max": self._dragging = False, True, False self._finiteRange = self._finiteRange[0], value self._last = None, value, None self._updateGammaPosition() self.sigRangeMoving.emit(*self._last) - elif event['label'] == 'Gamma': + elif event["label"] == "Gamma": self._dragging = False, False, True self._last = None, None, value self.sigRangeMoving.emit(*self._last) self._updateLutItem(self._finiteRange) - elif kind == 'markerMoved': + elif kind == "markerMoved": self.sigRangeMoved.emit(*self._last) self._plot.resetZoom() self._dragging = False, False, False @@ -616,20 +628,22 @@ class _ColormapHistogram(qt.QWidget): if posMin is not None and not self._dragging[0]: self._plot.addXMarker( posMin, - legend='Min', - text='Min', + legend="Min", + text="Min", draggable=isDraggable, color="blue", - constraint=self._plotMinMarkerConstraint) + constraint=self._plotMinMarkerConstraint, + ) self._updateGammaPosition() if posMax is not None and not self._dragging[1]: self._plot.addXMarker( posMax, - legend='Max', - text='\n\nMax', + legend="Max", + text="\n\nMax", draggable=isDraggable, color="blue", - constraint=self._plotMaxMarkerConstraint) + constraint=self._plotMaxMarkerConstraint, + ) self._updateLutItem((posMin, posMax)) self._plot.resetZoom() @@ -650,14 +664,14 @@ class _ColormapHistogram(qt.QWidget): if not self._dragging[2]: posRange = posMax - posMin if posRange > 0: - gammaPos = posMin + posRange * 0.5**(1/gamma) + gammaPos = posMin + posRange * 0.5 ** (1 / gamma) else: gammaPos = posMin marker = self._plot._getMarker( self._plot.addXMarker( gammaPos, - legend='Gamma', - text='\nGamma', + legend="Gamma", + text="\nGamma", draggable=True, color="blue", constraint=self._plotGammaMarkerConstraint, @@ -666,7 +680,7 @@ class _ColormapHistogram(qt.QWidget): marker.setZValue(2) else: try: - self._plot.removeMarker('Gamma') + self._plot.removeMarker("Gamma") except Exception: pass @@ -703,10 +717,9 @@ class _ColormapHistogram(qt.QWidget): self._lutItem2.setVisible(False) self._lutItem2.setColormap(normColormap) xx = numpy.geomspace(posMin, posMax, 256) - self._lutItem2.setData(x=xx, - y=self.__lutY, - value=self.__lutV, - copy=False) + self._lutItem2.setData( + x=xx, y=self.__lutY, value=self.__lutV, copy=False + ) self._lutItem2.setSymbol("|") self._lutItem2.setVisible(True) self._lutItem.setVisible(False) @@ -717,10 +730,8 @@ class _ColormapHistogram(qt.QWidget): self._lutItem2.setColormap(normColormap) xx = numpy.linspace(posMin, posMax, 256, endpoint=True) self._lutItem2.setData( - x=xx, - y=self.__lutY, - value=self.__lutV, - copy=False) + x=xx, y=self.__lutY, value=self.__lutV, copy=False + ) self._lutItem2.setSymbol("|") self._lutItem2.setVisible(True) self._lutItem.setVisible(False) @@ -750,15 +761,29 @@ class _ColormapHistogram(qt.QWidget): x = min(x, vmax) return x, y - def _setDataInPlotMode(self, mode): - if self._dataInPlotMode == mode: + def setDisplayMode(self, mode: str | DisplayMode): + mode = DisplayMode.from_value(mode) + if mode is DisplayMode.HISTOGRAM: + action = self._dataHistogramAction + elif mode is DisplayMode.RANGE: + action = self._dataRangeAction + else: + raise ValueError("Mode not supported") + action.setChecked(True) + self._displayModeChanged(action) + + def _setDisplayMode(self, mode): + if self._displayMode == mode: return - self._dataInPlotMode = mode - self._updateDataInPlot() + self._displayMode = mode + self._updateDisplayMode() - def _displayDataInPlotModeChanged(self, action): + def getDsiplayMode(self) -> DisplayMode: + return self._displayMode + + def _displayModeChanged(self, action): mode = action.data() - self._setDataInPlotMode(mode) + self._setDisplayMode(mode) def invalidateData(self): self._histogramData = {} @@ -766,8 +791,8 @@ class _ColormapHistogram(qt.QWidget): self._invalidated = True self.update() - def _updateDataInPlot(self): - mode = self._dataInPlotMode + def _updateDisplayMode(self): + mode = self._displayMode norm = self._getNorm() if norm == Colormap.LINEAR: @@ -780,38 +805,42 @@ class _ColormapHistogram(qt.QWidget): axis = self._plot.getXAxis() axis.setScale(scale) - if mode == _DataInPlotMode.RANGE: + if mode == DisplayMode.RANGE: dataRange = self._getNormalizedDataRange() xmin, xmax = dataRange if xmax is None or xmin is None: - self._plot.remove(legend='Data', kind='histogram') + self._plot.remove(legend="Data", kind="histogram") else: histogram = numpy.array([1]) bin_edges = numpy.array([xmin, xmax]) - self._plot.addHistogram(histogram, - bin_edges, - legend="Data", - color='gray', - align='center', - fill=True, - z=1) - - elif mode == _DataInPlotMode.HISTOGRAM: + self._plot.addHistogram( + histogram, + bin_edges, + legend="Data", + color="gray", + align="center", + fill=True, + z=1, + ) + + elif mode == DisplayMode.HISTOGRAM: histogram, bin_edges = self._getNormalizedHistogram() if histogram is None or bin_edges is None: - self._plot.remove(legend='Data', kind='histogram') + self._plot.remove(legend="Data", kind="histogram") else: histogram = numpy.array(histogram, copy=True) bin_edges = numpy.array(bin_edges, copy=True) - with numpy.errstate(invalid='ignore'): + with numpy.errstate(invalid="ignore"): norm_histogram = histogram / numpy.nanmax(histogram) - self._plot.addHistogram(norm_histogram, - bin_edges, - legend="Data", - color='gray', - align='center', - fill=True, - z=1) + self._plot.addHistogram( + norm_histogram, + bin_edges, + legend="Data", + color="gray", + align="center", + fill=True, + z=1, + ) else: _logger.error("Mode unsupported") @@ -830,7 +859,7 @@ class _ColormapHistogram(qt.QWidget): return norm def updateNormalization(self): - self._updateDataInPlot() + self._updateDisplayMode() self.update() @@ -887,16 +916,19 @@ class ColormapDialog(qt.QDialog): # Colormap row self._comboBoxColormap = ColormapNameComboBox(parent=self) - self._comboBoxColormap.currentIndexChanged[int].connect(self._comboBoxColormapUpdated) + self._comboBoxColormap.currentIndexChanged[int].connect( + self._comboBoxColormapUpdated + ) # Normalization row self._comboBoxNormalization = qt.QComboBox(parent=self) normalizations = [ - ('Linear', Colormap.LINEAR), - ('Gamma correction', Colormap.GAMMA), - ('Arcsinh', Colormap.ARCSINH), - ('Logarithmic', Colormap.LOGARITHM), - ('Square root', Colormap.SQRT)] + ("Linear", Colormap.LINEAR), + ("Gamma correction", Colormap.GAMMA), + ("Arcsinh", Colormap.ARCSINH), + ("Logarithmic", Colormap.LOGARITHM), + ("Square root", Colormap.SQRT), + ] for name, userData in normalizations: try: icon = icons.getQIcon("colormap-norm-%s" % userData) @@ -904,11 +936,12 @@ class ColormapDialog(qt.QDialog): icon = qt.QIcon() self._comboBoxNormalization.addItem(icon, name, userData) self._comboBoxNormalization.currentIndexChanged[int].connect( - self._normalizationUpdated) + self._normalizationUpdated + ) self._gammaSpinBox = qt.QDoubleSpinBox(parent=self) self._gammaSpinBox.setEnabled(False) - self._gammaSpinBox.setRange(0.01, 100.) + self._gammaSpinBox.setRange(0.01, 100.0) self._gammaSpinBox.setDecimals(4) if hasattr(qt.QDoubleSpinBox, "setStepType"): # Introduced in Qt 5.12 @@ -916,7 +949,7 @@ class ColormapDialog(qt.QDialog): else: self._gammaSpinBox.setSingleStep(0.1) self._gammaSpinBox.valueChanged.connect(self._gammaUpdated) - self._gammaSpinBox.setValue(2.) + self._gammaSpinBox.setValue(2.0) autoScaleCombo = _AutoscaleModeComboBox(self) autoScaleCombo.currentIndexChanged.connect(self._autoscaleModeUpdated) @@ -959,15 +992,17 @@ class ColormapDialog(qt.QDialog): self._histoWidget = _ColormapHistogram(self) self._histoWidget.sigRangeMoving.connect(self._histogramRangeMoving) self._histoWidget.sigRangeMoved.connect(self._histogramRangeMoved) - self._histoWidget.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding) + self._histoWidget.setSizePolicy( + qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding + ) # Scale to buttons self._visibleAreaButton = qt.QPushButton(self) self._visibleAreaButton.setEnabled(False) self._visibleAreaButton.setText("Visible Area") self._visibleAreaButton.clicked.connect( - self._handleScaleToVisibleAreaClicked, - type=qt.Qt.QueuedConnection) + self._handleScaleToVisibleAreaClicked, type=qt.Qt.QueuedConnection + ) # Place-holder for selected area ROI manager self._roiForColormapManager = None @@ -979,8 +1014,8 @@ class ColormapDialog(qt.QDialog): self._selectedAreaButton.setIcon(icons.getQIcon("add-shape-rectangle")) self._selectedAreaButton.setCheckable(True) self._selectedAreaButton.toggled.connect( - self._handleScaleToSelectionToggled, - type=qt.Qt.QueuedConnection) + self._handleScaleToSelectionToggled, type=qt.Qt.QueuedConnection + ) # define modal buttons types = qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel @@ -1003,8 +1038,9 @@ class ColormapDialog(qt.QDialog): self._buttonsNonModal.setFocus(qt.Qt.OtherFocusReason) # Set the colormap to default values - self.setColormap(Colormap(name='gray', normalization='linear', - vmin=None, vmax=None)) + self.setColormap( + Colormap(name="gray", normalization="linear", vmin=None, vmax=None) + ) self.setModal(self.isModal()) @@ -1023,19 +1059,23 @@ class ColormapDialog(qt.QDialog): layoutScale.addWidget(self._autoScaleCombo) layoutScale.addStretch() - formLayout = FormGridLayout(self) formLayout.setContentsMargins(10, 10, 10, 10) - formLayout.addRow('Colormap:', self._comboBoxColormap) - formLayout.addRow('Normalization:', self._comboBoxNormalization) - formLayout.addRow('Gamma:', self._gammaSpinBox) + formLayout.addRow("Colormap:", self._comboBoxColormap) + formLayout.addRow("Normalization:", self._comboBoxNormalization) + formLayout.addRow("Gamma:", self._gammaSpinBox) - formLayout.addItem(qt.QSpacerItem(1, 1, qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed)) + formLayout.addItem( + qt.QSpacerItem(1, 1, qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed) + ) formLayout.addRow(self._histoWidget) + formLayout.setRowStretch(formLayout.rowCount() - 1, 1) formLayout.addRow(rangeLayout) - formLayout.addItem(qt.QSpacerItem(1, 1, qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed)) - formLayout.addRow('Scale:', layoutScale) + formLayout.addItem( + qt.QSpacerItem(1, 1, qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed) + ) + formLayout.addRow("Scale:", layoutScale) formLayout.addRow("Fixed scale on:", self._scaleToAreaGroup) formLayout.addRow(self._buttonsModal) formLayout.addRow(self._buttonsNonModal) @@ -1054,6 +1094,9 @@ class ColormapDialog(qt.QDialog): self._applyColormap() + def getHistogramWidget(self): + return self._histoWidget + def _invalidateColormap(self): if self.isVisible(): self._applyColormap() @@ -1156,9 +1199,9 @@ class ColormapDialog(qt.QDialog): if dataRange is None or len(dataRange) != 3: qt.QMessageBox.warning( - None, "No Data", - "Image data does not contain any real value") - dataRange = 1., 1., 10. + None, "No Data", "Image data does not contain any real value" + ) + dataRange = 1.0, 1.0, 10.0 return dataRange @@ -1182,11 +1225,11 @@ class ColormapDialog(qt.QDialog): return None, None if data.ndim == 3: # RGB(A) images - _logger.info('Converting current image from RGB(A) to grayscale\ - in order to compute the intensity distribution') - data = (data[:,:, 0] * 0.299 + - data[:,:, 1] * 0.587 + - data[:,:, 2] * 0.114) + _logger.info( + "Converting current image from RGB(A) to grayscale\ + in order to compute the intensity distribution" + ) + data = data[:, :, 0] * 0.299 + data[:, :, 1] * 0.587 + data[:, :, 2] * 0.114 # bad hack: get 256 continuous bins in the case we have a B&W normalizeData = True @@ -1200,7 +1243,7 @@ class ColormapDialog(qt.QDialog): if normalizeData: if scale == Colormap.LOGARITHM: - with numpy.errstate(divide='ignore', invalid='ignore'): + with numpy.errstate(divide="ignore", invalid="ignore"): data = numpy.log10(data) if dataRange is not None: @@ -1231,7 +1274,7 @@ class ColormapDialog(qt.QDialog): bins = histogram.edges[0] if normalizeData: if scale == Colormap.LOGARITHM: - bins = 10 ** bins + bins = 10**bins return histogram.histo, bins def _getItem(self): @@ -1263,8 +1306,7 @@ class ColormapDialog(qt.QDialog): if oldArray is array: return - self._data = None - self._itemHolder = None + self.__resetItem() try: if item is None: self._item = None @@ -1272,6 +1314,7 @@ class ColormapDialog(qt.QDialog): if not isinstance(item, items.ColormapMixIn): self._item = None raise ValueError("Item %s is not supported" % item) + item.sigItemChanged.connect(self.__itemChanged) self._item = weakref.ref(item, self._itemAboutToFinalize) finally: self._syncScaleToButtonsEnabled() @@ -1279,6 +1322,20 @@ class ColormapDialog(qt.QDialog): self._histogramData = None self._invalidateData() + def __resetItem(self): + """Reset item and data used by the dialog""" + self._data = None + self._itemHolder = None + if self._item is not None: + item = self._item() + self._item = None + if item is not None: + item.sigItemChanged.disconnect(self.__itemChanged) + + def __itemChanged(self, event): + if event == items.ItemChangedType.DATA: + self._invalidateData() + def _getData(self): if self._data is None: return None @@ -1295,12 +1352,9 @@ class ColormapDialog(qt.QDialog): if oldData is data: return - self._item = None + self.__resetItem() self._syncScaleToButtonsEnabled() - if data is None: - self._data = None - self._itemHolder = None - else: + if data is not None: self._data = weakref.ref(data, self._dataAboutToFinalize) self._itemHolder = _DataRefHolder(self._data) @@ -1338,14 +1392,6 @@ class ColormapDialog(qt.QDialog): if self._item is weakref and qtinspect.isValid(self): self.setItem(None) - @deprecation.deprecated(reason="It is private data", since_version="0.13") - def getHistogram(self): - histo = self._getHistogram() - if histo is None: - return None - counts, bin_edges = histo - return numpy.array(counts, copy=True), numpy.array(bin_edges, copy=True) - def _getHistogram(self): """Returns the histogram defined by the dialog as metadata to describe the data in order to speed up the dialog. @@ -1429,7 +1475,7 @@ class ColormapDialog(qt.QDialog): (xmin, xmax, ymin, ymax) Rectangular region in data space """ if bounds is None: - return None # no-op + return # no-op colormap = self.getColormap() if colormap is None: @@ -1437,13 +1483,15 @@ class ColormapDialog(qt.QDialog): item = self._getItem() if not isinstance(item, items.ColormapMixIn): - return None # no-op + return # no-op data = item.getColormappedData(copy=False) - xmin, xmax, ymin, ymax = bounds if isinstance(item, items.ImageBase): + if data.ndim != 2: + return # no-op + ox, oy = item.getOrigin() sx, sy = item.getScale() @@ -1460,7 +1508,9 @@ class ColormapDialog(qt.QDialog): subset = data[ numpy.logical_and( numpy.logical_and(xmin <= x, x <= xmax), - numpy.logical_and(ymin <= y, y <= ymax))] + numpy.logical_and(ymin <= y, y <= ymax), + ) + ] if subset.size == 0: return # no-op @@ -1563,19 +1613,21 @@ class ColormapDialog(qt.QDialog): self._comboBoxColormap.setEnabled(colormap.isEditable()) with utils.blockSignals(self._comboBoxNormalization): index = self._comboBoxNormalization.findData( - colormap.getNormalization()) + colormap.getNormalization() + ) if index < 0: - _logger.error('Unsupported normalization: %s' % - colormap.getNormalization()) + _logger.error( + "Unsupported normalization: %s" % colormap.getNormalization() + ) else: self._comboBoxNormalization.setCurrentIndex(index) self._comboBoxNormalization.setEnabled(colormap.isEditable()) with utils.blockSignals(self._gammaSpinBox): - self._gammaSpinBox.setValue( - colormap.getGammaNormalizationParameter()) + self._gammaSpinBox.setValue(colormap.getGammaNormalizationParameter()) self._gammaSpinBox.setEnabled( - colormap.getNormalization() == Colormap.GAMMA and - colormap.isEditable()) + colormap.getNormalization() == Colormap.GAMMA + and colormap.isEditable() + ) with utils.blockSignals(self._autoScaleCombo): self._autoScaleCombo.setCurrentMode(colormap.getAutoscaleMode()) self._autoScaleCombo.setEnabled(colormap.isEditable()) @@ -1624,8 +1676,8 @@ class ColormapDialog(qt.QDialog): dataRange = self._getFiniteColormapRange() # Final colormap range - vmin = (dataRange[0] if not autoRange[0] else None) - vmax = (dataRange[1] if not autoRange[1] else None) + vmin = dataRange[0] if not autoRange[0] else None + vmax = dataRange[1] if not autoRange[1] else None with self._colormapChange: colormap = self.getColormap() @@ -1645,7 +1697,7 @@ class ColormapDialog(qt.QDialog): colormap = self.getColormap() if colormap is not None: normalization = self._comboBoxNormalization.itemData(index) - self._gammaSpinBox.setEnabled(normalization == 'gamma') + self._gammaSpinBox.setEnabled(normalization == "gamma") with self._colormapChange: colormap.setNormalization(normalization) @@ -1745,7 +1797,7 @@ class ColormapDialog(qt.QDialog): gamma = self._gammaSpinBox.minimum() else: gamma = numpy.clip( - numpy.log(0.5)/numpy.log((gammaPos - vmin) / (vmax - vmin)), + numpy.log(0.5) / numpy.log((gammaPos - vmin) / (vmax - vmin)), self._gammaSpinBox.minimum(), self._gammaSpinBox.maximum(), ) @@ -1771,7 +1823,9 @@ class ColormapDialog(qt.QDialog): def _syncScaleToButtonsEnabled(self): """Set the state of scale to buttons according to current item and colormap""" colormap = self.getColormap() - enabled = self._item is not None and colormap is not None and colormap.isEditable() + enabled = ( + self._item is not None and colormap is not None and colormap.isEditable() + ) self._scaleToAreaGroup.setVisible(enabled) self._visibleAreaButton.setEnabled(enabled) if not enabled: @@ -1817,10 +1871,14 @@ class ColormapDialog(qt.QDialog): self._roiForColormapManager = RegionOfInterestManager(parent=plotWidget) cmap = self.getColormap() self._roiForColormapManager.setColor( - 'black' if cmap is None else cursorColorForColormap(cmap.getName())) + "black" if cmap is None else cursorColorForColormap(cmap.getName()) + ) self._roiForColormapManager.sigInteractiveModeFinished.connect( - self.__roiInteractiveModeFinished) - self._roiForColormapManager.sigInteractiveRoiFinalized.connect(self.__roiFinalized) + self.__roiInteractiveModeFinished + ) + self._roiForColormapManager.sigInteractiveRoiFinalized.connect( + self.__roiFinalized + ) self._roiForColormapManager.start(RectangleROI) def __roiInteractiveModeFinished(self): @@ -1830,7 +1888,7 @@ class ColormapDialog(qt.QDialog): if roi is not None: ox, oy = roi.getOrigin() width, height = roi.getSize() - self.setColormapRangeFromDataBounds((ox, ox+width, oy, oy+height)) + self.setColormapRangeFromDataBounds((ox, ox + width, oy, oy + height)) # clear ROI self._roiForColormapManager.removeRoi(roi) diff --git a/src/silx/gui/dialog/DataFileDialog.py b/src/silx/gui/dialog/DataFileDialog.py index 75b1721..4c6891e 100644 --- a/src/silx/gui/dialog/DataFileDialog.py +++ b/src/silx/gui/dialog/DataFileDialog.py @@ -36,8 +36,6 @@ from silx.gui.hdf5.Hdf5Formatter import Hdf5Formatter import silx.io from .AbstractDataFileDialog import AbstractDataFileDialog -import fabio - _logger = logging.getLogger(__name__) @@ -336,4 +334,4 @@ class DataFileDialog(AbstractDataFileDialog): selection widget (basically the data from the browsing widget) :rtype: bool """ - return u"" + return "" diff --git a/src/silx/gui/dialog/DatasetDialog.py b/src/silx/gui/dialog/DatasetDialog.py index 5d8af0d..1bc2722 100644 --- a/src/silx/gui/dialog/DatasetDialog.py +++ b/src/silx/gui/dialog/DatasetDialog.py @@ -60,17 +60,22 @@ class DatasetDialog(_Hdf5ItemSelectionDialog): print("Operation cancelled :(") """ + def __init__(self, parent=None): _Hdf5ItemSelectionDialog.__init__(self, parent) # customization for groups self.setWindowTitle("HDF5 dataset selection") - self._header.setSections([self._model.NAME_COLUMN, - self._model.NODE_COLUMN, - self._model.LINK_COLUMN, - self._model.TYPE_COLUMN, - self._model.SHAPE_COLUMN]) + self._header.setSections( + [ + self._model.NAME_COLUMN, + self._model.NODE_COLUMN, + self._model.LINK_COLUMN, + self._model.TYPE_COLUMN, + self._model.SHAPE_COLUMN, + ] + ) self._selectDatasetStatusText = "Select a dataset or type a new dataset name" def setMode(self, mode): @@ -80,7 +85,9 @@ class DatasetDialog(_Hdf5ItemSelectionDialog): """ _Hdf5ItemSelectionDialog.setMode(self, mode) if mode == DatasetDialog.SaveMode: - self._selectDatasetStatusText = "Select a dataset or type a new dataset name" + self._selectDatasetStatusText = ( + "Select a dataset or type a new dataset name" + ) elif mode == DatasetDialog.LoadMode: self._selectDatasetStatusText = "Select a dataset" @@ -110,11 +117,11 @@ class DatasetDialog(_Hdf5ItemSelectionDialog): isDatasetSelected = True if isDatasetSelected: - self._selectedUrl = DataUrl(file_path=node.local_filename, - data_path=data_path) + self._selectedUrl = DataUrl( + file_path=node.local_filename, data_path=data_path + ) self._okButton.setEnabled(True) - self._labelSelection.setText( - self._selectedUrl.path()) + self._labelSelection.setText(self._selectedUrl.path()) else: self._selectedUrl = None self._okButton.setEnabled(False) diff --git a/src/silx/gui/dialog/FileTypeComboBox.py b/src/silx/gui/dialog/FileTypeComboBox.py index 0ffc3a5..85ad3b1 100644 --- a/src/silx/gui/dialog/FileTypeComboBox.py +++ b/src/silx/gui/dialog/FileTypeComboBox.py @@ -1,6 +1,6 @@ # /*########################################################################## # -# Copyright (c) 2016 European Synchrotron Radiation Facility +# Copyright (c) 2016-2023 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,12 +30,13 @@ __license__ = "MIT" __date__ = "17/01/2019" import fabio +from fabio import fabioutils + import silx.io from silx.gui import qt class Codec(object): - def __init__(self, any_fabio=False, any_silx=False, fabio_codec=None, auto=False): self.__any_fabio = any_fabio self.__any_silx = any_silx @@ -63,7 +64,7 @@ class FileTypeComboBox(qt.QComboBox): CODEC_ROLE = qt.Qt.UserRole + 2 - INDENTATION = u"\u2022 " + INDENTATION = "\u2022 " def __init__(self, parent=None): qt.QComboBox.__init__(self, parent) @@ -134,20 +135,13 @@ 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 compressedExtension in fabioutils.COMPRESSED_EXTENSIONS: for extension in reader.DEFAULT_EXTENSIONS: yield "*.%s.%s" % (extension, compressedExtension) @@ -163,7 +157,9 @@ class FileTypeComboBox(qt.QComboBox): allExtensions.update(ext) if ext == []: ext = ["*"] - extensions.append((reader.DESCRIPTION, displayext, ext, reader.codec_name())) + extensions.append( + (reader.DESCRIPTION, displayext, ext, reader.codec_name()) + ) extensions = list(sorted(extensions)) allExtensions = list(sorted(list(allExtensions))) @@ -176,7 +172,9 @@ class FileTypeComboBox(qt.QComboBox): description, displayExt, allExt, _codecName = e index = self.count() if len(e[1]) < 10: - self.addItem("%s%s (%s)" % (self.INDENTATION, description, " ".join(displayExt))) + self.addItem( + "%s%s (%s)" % (self.INDENTATION, description, " ".join(displayExt)) + ) else: self.addItem("%s%s" % (self.INDENTATION, description)) codec = Codec(fabio_codec=_codecName) diff --git a/src/silx/gui/dialog/GroupDialog.py b/src/silx/gui/dialog/GroupDialog.py index fb85d83..ca669f2 100644 --- a/src/silx/gui/dialog/GroupDialog.py +++ b/src/silx/gui/dialog/GroupDialog.py @@ -54,8 +54,7 @@ class _Hdf5ItemSelectionDialog(qt.QDialog): self._tree = Hdf5TreeView(self) self._tree.setSelectionMode(qt.QAbstractItemView.SingleSelection) self._tree.activated.connect(self._onActivation) - self._tree.selectionModel().selectionChanged.connect( - self._onSelectionChange) + self._tree.selectionModel().selectionChanged.connect(self._onSelectionChange) self._model = self._tree.findHdf5TreeModel() @@ -67,10 +66,9 @@ class _Hdf5ItemSelectionDialog(qt.QDialog): self._labelNewItem.setText("Create new item in selected group (optional):") self._lineEditNewItem = qt.QLineEdit(self._newItemWidget) self._lineEditNewItem.setToolTip( - "Specify the name of a new item " - "to be created in the selected group.") - self._lineEditNewItem.textChanged.connect( - self._onNewItemNameChange) + "Specify the name of a new item " "to be created in the selected group." + ) + self._lineEditNewItem.textChanged.connect(self._onNewItemNameChange) newItemLayout.addWidget(self._labelNewItem) newItemLayout.addWidget(self._lineEditNewItem) @@ -151,11 +149,11 @@ class _Hdf5ItemSelectionDialog(qt.QDialog): if not data_path.endswith("/"): data_path += "/" data_path += subgroupName.lstrip("/") - self._selectedUrl = DataUrl(file_path=node.local_filename, - data_path=data_path) + self._selectedUrl = DataUrl( + file_path=node.local_filename, data_path=data_path + ) self._okButton.setEnabled(True) - self._labelSelection.setText( - self._selectedUrl.path()) + self._labelSelection.setText(self._selectedUrl.path()) def getSelectedDataUrl(self): """Return a :class:`DataUrl` with a file path and a data path. @@ -189,15 +187,16 @@ class GroupDialog(_Hdf5ItemSelectionDialog): print("Operation cancelled :(") """ + def __init__(self, parent=None): _Hdf5ItemSelectionDialog.__init__(self, parent) # customization for groups self.setWindowTitle("HDF5 group selection") - self._header.setSections([self._model.NAME_COLUMN, - self._model.NODE_COLUMN, - self._model.LINK_COLUMN]) + self._header.setSections( + [self._model.NAME_COLUMN, self._model.NODE_COLUMN, self._model.LINK_COLUMN] + ) def _onActivation(self, idx): # double-click or enter press: filter for groups @@ -218,11 +217,11 @@ class GroupDialog(_Hdf5ItemSelectionDialog): if not data_path.endswith("/"): data_path += "/" data_path += subgroupName.lstrip("/") - self._selectedUrl = DataUrl(file_path=node.local_filename, - data_path=data_path) + self._selectedUrl = DataUrl( + file_path=node.local_filename, data_path=data_path + ) self._okButton.setEnabled(True) - self._labelSelection.setText( - self._selectedUrl.path()) + self._labelSelection.setText(self._selectedUrl.path()) else: self._selectedUrl = None self._okButton.setEnabled(False) diff --git a/src/silx/gui/dialog/ImageFileDialog.py b/src/silx/gui/dialog/ImageFileDialog.py index ed455f3..e7ce38f 100644 --- a/src/silx/gui/dialog/ImageFileDialog.py +++ b/src/silx/gui/dialog/ImageFileDialog.py @@ -198,7 +198,9 @@ class _ImagePreview(qt.QWidget): axis = self.__plot.getXAxis() axis.setLimitsConstraints(midWidth - widthContraint, midWidth + widthContraint) axis = self.__plot.getYAxis() - axis.setLimitsConstraints(midHeight - heightContraint, midHeight + heightContraint) + axis.setLimitsConstraints( + midHeight - heightContraint, midHeight + heightContraint + ) def __imageItem(self): image = self.__plot.getImage("data") @@ -340,14 +342,14 @@ class ImageFileDialog(AbstractDataFileDialog): """ destination = self.__formatShape(dataAfterSelection.shape) source = self.__formatShape(dataBeforeSelection.shape) - return u"%s \u2192 %s" % (source, destination) + return "%s \u2192 %s" % (source, destination) def __formatShape(self, shape): result = [] for s in shape: if isinstance(s, slice): - v = u"\u2026" + v = "\u2026" else: v = str(s) result.append(v) - return u" \u00D7 ".join(result) + return " \u00D7 ".join(result) diff --git a/src/silx/gui/dialog/SafeFileIconProvider.py b/src/silx/gui/dialog/SafeFileIconProvider.py index 141bedf..7022876 100644 --- a/src/silx/gui/dialog/SafeFileIconProvider.py +++ b/src/silx/gui/dialog/SafeFileIconProvider.py @@ -91,6 +91,7 @@ class SafeFileIconProvider(qt.QFileIconProvider): def __windowsDriveTypeId(self, info): try: import ctypes + path = info.filePath() dtype = ctypes.cdll.kernel32.GetDriveTypeW(path) except Exception: diff --git a/src/silx/gui/dialog/SafeFileSystemModel.py b/src/silx/gui/dialog/SafeFileSystemModel.py index b9f3913..7cacc1e 100644 --- a/src/silx/gui/dialog/SafeFileSystemModel.py +++ b/src/silx/gui/dialog/SafeFileSystemModel.py @@ -41,7 +41,6 @@ _logger = logging.getLogger(__name__) class _Item(object): - def __init__(self, fileInfo): self.__fileInfo = fileInfo self.__parent = None @@ -101,7 +100,9 @@ class _Item(object): elif self.isDrive(): path = self.__fileInfo.filePath() else: - path = os.path.join(self.parent().absoluteFilePath(), self.__fileInfo.fileName()) + path = os.path.join( + self.parent().absoluteFilePath(), self.__fileInfo.fileName() + ) if path == "": return "/" self.__absolutePath = path @@ -236,7 +237,9 @@ class _RawFileSystemModel(qt.QAbstractItemModel): self.__header = "Name", "Size", "Type", "Last modification" self.__currentPath = "" self.__iconProvider = SafeFileIconProvider() - self.__directoryLoadedSync.connect(self.__emitDirectoryLoaded, qt.Qt.QueuedConnection) + self.__directoryLoadedSync.connect( + self.__emitDirectoryLoaded, qt.Qt.QueuedConnection + ) def headerData(self, section, orientation, role=qt.Qt.DisplayRole): if orientation == qt.Qt.Horizontal: @@ -496,7 +499,7 @@ class _RawFileSystemModel(qt.QAbstractItemModel): return def setReadOnly(self, enable): - assert(enable is True) + assert enable is True def isReadOnly(self): return False @@ -612,20 +615,20 @@ class SafeFileSystemModel(qt.QSortFilterProxyModel): filterPermissions = (filters & qt.QDir.PermissionMask) != 0 if filterPermissions and (filters & (qt.QDir.Dirs | qt.QDir.Files)): - if (filters & qt.QDir.Readable): + if filters & qt.QDir.Readable: # Hide unreadable if not fileInfo.isReadable(): return False - if (filters & qt.QDir.Writable): + if filters & qt.QDir.Writable: # Hide unwritable if not fileInfo.isWritable(): return False - if (filters & qt.QDir.Executable): + if filters & qt.QDir.Executable: # Hide unexecutable if not fileInfo.isExecutable(): return False - if (filters & qt.QDir.NoSymLinks): + if filters & qt.QDir.NoSymLinks: # Hide sym links if fileInfo.isSymLink(): return False @@ -711,7 +714,9 @@ class SafeFileSystemModel(qt.QSortFilterProxyModel): def setNameFilters(self, filters): self.__nameFilters = [] isCaseSensitive = self.__filters & qt.QDir.CaseSensitive - caseSensitive = qt.Qt.CaseSensitive if isCaseSensitive else qt.Qt.CaseInsensitive + caseSensitive = ( + qt.Qt.CaseSensitive if isCaseSensitive else qt.Qt.CaseInsensitive + ) for f in filters: reg = qt.QRegExp(f, caseSensitive, qt.QRegExp.Wildcard) self.__nameFilters.append(reg) @@ -730,7 +735,7 @@ class SafeFileSystemModel(qt.QSortFilterProxyModel): self.invalidate() def setReadOnly(self, enable): - assert(enable is True) + assert enable is True def isReadOnly(self): return False diff --git a/src/silx/gui/dialog/test/test_colormapdialog.py b/src/silx/gui/dialog/test/test_colormapdialog.py index 1bfd584..1afafc0 100644 --- a/src/silx/gui/dialog/test/test_colormapdialog.py +++ b/src/silx/gui/dialog/test/test_colormapdialog.py @@ -1,6 +1,6 @@ # /*########################################################################## # -# Copyright (c) 2016-2022 European Synchrotron Radiation Facility +# Copyright (c) 2016-2024 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 @@ -29,371 +29,369 @@ __date__ = "09/11/2018" import pytest -import weakref from silx.gui import qt from silx.gui.dialog import ColormapDialog -from silx.gui.utils.testutils import TestCaseQt from silx.gui.colors import Colormap, preferredColormaps -from silx.utils.testutils import ParametricTestCase from silx.gui.plot.items.image import ImageData import numpy -@pytest.fixture -def colormap(): - colormap = Colormap(name='gray', - vmin=10.0, vmax=20.0, - normalization='linear') - yield colormap +def testGUIEdition(qWidgetFactory): + """Make sure the colormap is correctly edited and also that the + modification are correctly updated if an other colormapdialog is + editing the same colormap""" + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + dialog.setColormap(colormap) + dialog2 = qWidgetFactory(ColormapDialog.ColormapDialog) + dialog2.setColormap(colormap) + + dialog._comboBoxColormap._setCurrentName("red") + dialog._comboBoxNormalization.setCurrentIndex( + dialog._comboBoxNormalization.findData(Colormap.LOGARITHM) + ) + assert colormap.getName() == "red" + assert dialog.getColormap().getName() == "red" + assert colormap.getNormalization() == "log" + assert colormap.getVMin() == 10 + assert colormap.getVMax() == 20 + # checked second colormap dialog + assert dialog2._comboBoxColormap.getCurrentName() == "red" + assert dialog2._comboBoxNormalization.currentData() == Colormap.LOGARITHM + assert int(dialog2._minValue.getValue()) == 10 + assert int(dialog2._maxValue.getValue()) == 20 + + +def testGUIModalOk(qapp, qapp_utils, qWidgetFactory): + """Make sure the colormap is modified if gone through accept""" + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + assert colormap.isAutoscale() is False + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + dialog.setModal(True) + qapp.processEvents() + + dialog.setColormap(colormap) + assert colormap.getVMin() is not None + dialog._minValue.sigAutoScaleChanged.emit(True) + assert colormap.getVMin() is None + dialog._maxValue.sigAutoScaleChanged.emit(True) + qapp_utils.mouseClick( + widget=dialog._buttonsModal.button(qt.QDialogButtonBox.Ok), + button=qt.Qt.LeftButton, + ) + assert colormap.getVMin() is None + assert colormap.getVMax() is None + assert colormap.isAutoscale() is True + + +def testGUIModalCancel(qapp, qapp_utils, qWidgetFactory): + """Make sure the colormap is not modified if gone through reject""" + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + assert colormap.isAutoscale() is False + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + dialog.setModal(True) + qapp.processEvents() + + dialog.setColormap(colormap) + assert colormap.getVMin() is not None + dialog._minValue.sigAutoScaleChanged.emit(True) + assert colormap.getVMin() is None + qapp_utils.mouseClick( + widget=dialog._buttonsModal.button(qt.QDialogButtonBox.Cancel), + button=qt.Qt.LeftButton, + ) + assert colormap.getVMin() is not None + + +def testGUIModalClose(qapp, qapp_utils, qWidgetFactory): + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + assert colormap.isAutoscale() is False + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + dialog.setModal(False) + qapp.processEvents() + dialog.setColormap(colormap) + assert colormap.getVMin() is not None + dialog._minValue.sigAutoScaleChanged.emit(True) + assert colormap.getVMin() is None + qapp_utils.mouseClick( + widget=dialog._buttonsNonModal.button(qt.QDialogButtonBox.Close), + button=qt.Qt.LeftButton, + ) + assert colormap.getVMin() is None + + +def testGUIModalReset(qapp, qapp_utils, qWidgetFactory): + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + assert colormap.isAutoscale() is False + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + dialog.setModal(False) + dialog.show() + qapp.processEvents() + dialog.setColormap(colormap) + assert colormap.getVMin() is not None + dialog._minValue.sigAutoScaleChanged.emit(True) + assert colormap.getVMin() is None + qapp_utils.mouseClick( + widget=dialog._buttonsNonModal.button(qt.QDialogButtonBox.Reset), + button=qt.Qt.LeftButton, + ) + assert colormap.getVMin() is not None + dialog.close() + + +def testGUIClose(qapp, qWidgetFactory): + """Make sure the colormap is modify if go through reject""" + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + assert colormap.isAutoscale() is False + qapp.processEvents() + + dialog.setColormap(colormap) + assert colormap.getVMin() is not None + dialog._minValue.sigAutoScaleChanged.emit(True) + assert colormap.getVMin() is None + dialog.close() + qapp.processEvents() + assert colormap.getVMin() is None + + +@pytest.mark.parametrize("norm", Colormap.NORMALIZATIONS) +@pytest.mark.parametrize("autoscale", (True, False)) +def testSetColormapIsCorrect(norm, autoscale, qapp, qWidgetFactory): + """Make sure the interface fir the colormap when set a new colormap""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + colormap.setName("red") + if autoscale is True: + colormap.setVRange(None, None) + else: + colormap.setVRange(11, 101) + colormap.setNormalization(norm) + dialog.setColormap(colormap) + qapp.processEvents() -@pytest.fixture -def colormapDialog(qapp): - dialog = ColormapDialog.ColormapDialog() - dialog.setAttribute(qt.Qt.WA_DeleteOnClose) - yield weakref.proxy(dialog) + assert dialog._comboBoxNormalization.currentData() == norm + assert dialog._comboBoxColormap.getCurrentName() == "red" + assert dialog._minValue.isAutoChecked() == autoscale + assert dialog._maxValue.isAutoChecked() == autoscale + if autoscale is False: + assert dialog._minValue.getValue() == 11 + assert dialog._maxValue.getValue() == 101 + assert dialog._minValue.isEnabled() + assert dialog._maxValue.isEnabled() + else: + assert dialog._minValue._numVal.isReadOnly() + assert dialog._maxValue._numVal.isReadOnly() + + +def testColormapDel(qapp, qWidgetFactory): + """Check behavior if the colormap has been deleted outside. For now + we make sure the colormap is still running and nothing more""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + colormap = Colormap(name="gray") + dialog.setColormap(colormap) qapp.processEvents() - from silx.gui.qt import inspect - if inspect.isValid(dialog): - dialog.close() - del dialog - qapp.processEvents() + colormap = None + assert dialog.getColormap() is None + dialog._comboBoxColormap._setCurrentName("blue") -@pytest.fixture -def colormap_class_attr(request, qapp_utils, colormap, colormapDialog): - """Provides few fixtures to a class as class attribute - Used as transition from TestCase to pytest +def testColormapEditedOutside(qapp, qWidgetFactory): + """Make sure the GUI is still up to date if the colormap is modified + outside""" + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + dialog.setColormap(colormap) + qapp.processEvents() + + colormap.setName("red") + assert dialog._comboBoxColormap.getCurrentName() == "red" + colormap.setNormalization(Colormap.LOGARITHM) + assert dialog._comboBoxNormalization.currentData() == Colormap.LOGARITHM + colormap.setVRange(11, 201) + assert dialog._minValue.getValue() == 11 + assert dialog._maxValue.getValue() == 201 + assert not (dialog._minValue._numVal.isReadOnly()) + assert not (dialog._maxValue._numVal.isReadOnly()) + assert not (dialog._minValue.isAutoChecked()) + assert not (dialog._maxValue.isAutoChecked()) + colormap.setVRange(None, None) + qapp.processEvents() + + assert dialog._minValue._numVal.isReadOnly() + assert dialog._maxValue._numVal.isReadOnly() + assert dialog._minValue.isAutoChecked() + assert dialog._maxValue.isAutoChecked() + + +def testSetColormapScenario(qWidgetFactory): + """Test of a simple scenario of a colormap dialog editing several + colormap""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + colormap = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + colormap1 = Colormap(name="gray", vmin=10.0, vmax=20.0, normalization="linear") + colormap2 = Colormap(name="red", vmin=10.0, vmax=20.0, normalization="log") + colormap3 = Colormap(name="blue", vmin=None, vmax=None, normalization="linear") + + dialog.setColormap(colormap) + dialog.setColormap(colormap1) + del colormap1 + dialog.setColormap(colormap2) + del colormap2 + dialog.setColormap(colormap3) + del colormap3 + + +def testNotPreferredColormap(qapp, qWidgetFactory): + """Test that the colormapEditor is able to edit a colormap which is not + part of the 'prefered colormap' """ - request.cls.qapp_utils = qapp_utils - request.cls.colormap = colormap - request.cls.colormapDiag = colormapDialog - yield - request.cls.qapp_utils = None - request.cls.colormap = None - request.cls.colormapDiag = None - - -@pytest.mark.usefixtures("colormap_class_attr") -class TestColormapDialog(TestCaseQt, ParametricTestCase): - - def testGUIEdition(self): - """Make sure the colormap is correctly edited and also that the - modification are correctly updated if an other colormapdialog is - editing the same colormap""" - colormapDiag2 = ColormapDialog.ColormapDialog() - colormapDiag2.setAttribute(qt.Qt.WA_DeleteOnClose) - colormapDiag2.setColormap(self.colormap) - colormapDiag2.show() - self.colormapDiag.setColormap(self.colormap) - self.colormapDiag.show() - self.qapp.processEvents() - - self.colormapDiag._comboBoxColormap._setCurrentName('red') - self.colormapDiag._comboBoxNormalization.setCurrentIndex( - self.colormapDiag._comboBoxNormalization.findData(Colormap.LOGARITHM)) - self.assertTrue(self.colormap.getName() == 'red') - self.assertTrue(self.colormapDiag.getColormap().getName() == 'red') - self.assertTrue(self.colormap.getNormalization() == 'log') - self.assertTrue(self.colormap.getVMin() == 10) - self.assertTrue(self.colormap.getVMax() == 20) - # checked second colormap dialog - self.assertTrue(colormapDiag2._comboBoxColormap.getCurrentName() == 'red') - self.assertEqual(colormapDiag2._comboBoxNormalization.currentData(), - Colormap.LOGARITHM) - self.assertTrue(int(colormapDiag2._minValue.getValue()) == 10) - self.assertTrue(int(colormapDiag2._maxValue.getValue()) == 20) - colormapDiag2.close() - del colormapDiag2 - self.qapp.processEvents() - - def testGUIModalOk(self): - """Make sure the colormap is modified if gone through accept""" - assert self.colormap.isAutoscale() is False - self.colormapDiag.setModal(True) - self.colormapDiag.show() - self.qapp.processEvents() - self.colormapDiag.setColormap(self.colormap) - self.assertTrue(self.colormap.getVMin() is not None) - self.colormapDiag._minValue.sigAutoScaleChanged.emit(True) - self.assertTrue(self.colormap.getVMin() is None) - self.colormapDiag._maxValue.sigAutoScaleChanged.emit(True) - self.mouseClick( - widget=self.colormapDiag._buttonsModal.button(qt.QDialogButtonBox.Ok), - button=qt.Qt.LeftButton - ) - self.assertTrue(self.colormap.getVMin() is None) - self.assertTrue(self.colormap.getVMax() is None) - self.assertTrue(self.colormap.isAutoscale() is True) - - def testGUIModalCancel(self): - """Make sure the colormap is not modified if gone through reject""" - assert self.colormap.isAutoscale() is False - self.colormapDiag.setModal(True) - self.colormapDiag.show() - self.qapp.processEvents() - self.colormapDiag.setColormap(self.colormap) - self.assertTrue(self.colormap.getVMin() is not None) - self.colormapDiag._minValue.sigAutoScaleChanged.emit(True) - self.assertTrue(self.colormap.getVMin() is None) - self.mouseClick( - widget=self.colormapDiag._buttonsModal.button(qt.QDialogButtonBox.Cancel), - button=qt.Qt.LeftButton - ) - self.assertTrue(self.colormap.getVMin() is not None) - - def testGUIModalClose(self): - assert self.colormap.isAutoscale() is False - self.colormapDiag.setModal(False) - self.colormapDiag.show() - self.qapp.processEvents() - self.colormapDiag.setColormap(self.colormap) - self.assertTrue(self.colormap.getVMin() is not None) - self.colormapDiag._minValue.sigAutoScaleChanged.emit(True) - self.assertTrue(self.colormap.getVMin() is None) - self.mouseClick( - widget=self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Close), - button=qt.Qt.LeftButton - ) - self.assertTrue(self.colormap.getVMin() is None) - - def testGUIModalReset(self): - assert self.colormap.isAutoscale() is False - self.colormapDiag.setModal(False) - self.colormapDiag.show() - self.qapp.processEvents() - self.colormapDiag.setColormap(self.colormap) - self.assertTrue(self.colormap.getVMin() is not None) - self.colormapDiag._minValue.sigAutoScaleChanged.emit(True) - self.assertTrue(self.colormap.getVMin() is None) - self.mouseClick( - widget=self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset), - button=qt.Qt.LeftButton - ) - self.assertTrue(self.colormap.getVMin() is not None) - self.colormapDiag.close() - - def testGUIClose(self): - """Make sure the colormap is modify if go through reject""" - assert self.colormap.isAutoscale() is False - self.colormapDiag.show() - self.qapp.processEvents() - self.colormapDiag.setColormap(self.colormap) - self.assertTrue(self.colormap.getVMin() is not None) - self.colormapDiag._minValue.sigAutoScaleChanged.emit(True) - self.assertTrue(self.colormap.getVMin() is None) - self.colormapDiag.close() - self.qapp.processEvents() - self.assertTrue(self.colormap.getVMin() is None) - - def testSetColormapIsCorrect(self): - """Make sure the interface fir the colormap when set a new colormap""" - self.colormap.setName('red') - self.colormapDiag.show() - self.qapp.processEvents() - for norm in (Colormap.NORMALIZATIONS): - for autoscale in (True, False): - if autoscale is True: - self.colormap.setVRange(None, None) - else: - self.colormap.setVRange(11, 101) - self.colormap.setNormalization(norm) - with self.subTest(colormap=self.colormap): - self.colormapDiag.setColormap(self.colormap) - self.assertEqual( - self.colormapDiag._comboBoxNormalization.currentData(), norm) - self.assertTrue( - self.colormapDiag._comboBoxColormap.getCurrentName() == 'red') - self.assertTrue( - self.colormapDiag._minValue.isAutoChecked() == autoscale) - self.assertTrue( - self.colormapDiag._maxValue.isAutoChecked() == autoscale) - if autoscale is False: - self.assertTrue(self.colormapDiag._minValue.getValue() == 11) - self.assertTrue(self.colormapDiag._maxValue.getValue() == 101) - self.assertTrue(self.colormapDiag._minValue.isEnabled()) - self.assertTrue(self.colormapDiag._maxValue.isEnabled()) - else: - self.assertTrue(self.colormapDiag._minValue._numVal.isReadOnly()) - self.assertTrue(self.colormapDiag._maxValue._numVal.isReadOnly()) - - def testColormapDel(self): - """Check behavior if the colormap has been deleted outside. For now - we make sure the colormap is still running and nothing more""" - colormap = Colormap(name='gray') - self.colormapDiag.setColormap(colormap) - self.colormapDiag.show() - self.qapp.processEvents() - colormap = None - self.assertTrue(self.colormapDiag.getColormap() is None) - self.colormapDiag._comboBoxColormap._setCurrentName('blue') - - def testColormapEditedOutside(self): - """Make sure the GUI is still up to date if the colormap is modified - outside""" - self.colormapDiag.setColormap(self.colormap) - self.colormapDiag.show() - self.qapp.processEvents() - - self.colormap.setName('red') - self.assertTrue( - self.colormapDiag._comboBoxColormap.getCurrentName() == 'red') - self.colormap.setNormalization(Colormap.LOGARITHM) - self.assertEqual(self.colormapDiag._comboBoxNormalization.currentData(), - Colormap.LOGARITHM) - self.colormap.setVRange(11, 201) - self.assertTrue(self.colormapDiag._minValue.getValue() == 11) - self.assertTrue(self.colormapDiag._maxValue.getValue() == 201) - self.assertFalse(self.colormapDiag._minValue._numVal.isReadOnly()) - self.assertFalse(self.colormapDiag._maxValue._numVal.isReadOnly()) - self.assertFalse(self.colormapDiag._minValue.isAutoChecked()) - self.assertFalse(self.colormapDiag._maxValue.isAutoChecked()) - self.colormap.setVRange(None, None) - self.qapp.processEvents() - self.assertTrue(self.colormapDiag._minValue._numVal.isReadOnly()) - self.assertTrue(self.colormapDiag._maxValue._numVal.isReadOnly()) - self.assertTrue(self.colormapDiag._minValue.isAutoChecked()) - self.assertTrue(self.colormapDiag._maxValue.isAutoChecked()) - - def testSetColormapScenario(self): - """Test of a simple scenario of a colormap dialog editing several - colormap""" - colormap1 = Colormap(name='gray', vmin=10.0, vmax=20.0, - normalization='linear') - colormap2 = Colormap(name='red', vmin=10.0, vmax=20.0, - normalization='log') - colormap3 = Colormap(name='blue', vmin=None, vmax=None, - normalization='linear') - self.colormapDiag.setColormap(self.colormap) - self.colormapDiag.setColormap(colormap1) - del colormap1 - self.colormapDiag.setColormap(colormap2) - del colormap2 - self.colormapDiag.setColormap(colormap3) - del colormap3 - - def testNotPreferredColormap(self): - """Test that the colormapEditor is able to edit a colormap which is not - part of the 'prefered colormap' - """ - def getFirstNotPreferredColormap(): - cms = Colormap.getSupportedColormaps() - preferred = preferredColormaps() - for cm in cms: - if cm not in preferred: - return cm - return None - - colormapName = getFirstNotPreferredColormap() - assert colormapName is not None - colormap = Colormap(name=colormapName) - self.colormapDiag.setColormap(colormap) - self.colormapDiag.show() - self.qapp.processEvents() - cb = self.colormapDiag._comboBoxColormap - self.assertTrue(cb.getCurrentName() == colormapName) - cb.setCurrentIndex(0) - index = cb.findLutName(colormapName) - assert index != 0 # if 0 then the rest of the test has no sense - cb.setCurrentIndex(index) - self.assertTrue(cb.getCurrentName() == colormapName) - - def testColormapEditableMode(self): - """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.qapp.processEvents() - self.colormapDiag.setColormap(colormap) - for editable in (True, False): - with self.subTest(editable=editable): - colormap.setEditable(editable) - self.assertTrue( - self.colormapDiag._comboBoxColormap.isEnabled() is editable) - self.assertTrue( - self.colormapDiag._minValue.isEnabled() is editable) - self.assertTrue( - self.colormapDiag._maxValue.isEnabled() is editable) - self.assertTrue( - self.colormapDiag._comboBoxNormalization.isEnabled() is editable) - - # Make sure the reset button is also set to enable when edition mode is - # False - self.colormapDiag.setModal(False) - colormap.setEditable(True) - self.colormapDiag._comboBoxNormalization.setCurrentIndex( - self.colormapDiag._comboBoxNormalization.findData(Colormap.LOGARITHM)) - resetButton = self.colormapDiag._buttonsNonModal.button(qt.QDialogButtonBox.Reset) - self.assertTrue(resetButton.isEnabled()) - colormap.setEditable(False) - self.assertFalse(resetButton.isEnabled()) - - def testImageData(self): - data = numpy.random.rand(5, 5) - self.colormapDiag.setData(data) - - def testEmptyData(self): - data = numpy.empty((10, 0)) - self.colormapDiag.setData(data) - - def testNoneData(self): - data = numpy.random.rand(5, 5) - self.colormapDiag.setData(data) - self.colormapDiag.setData(None) - - def testImageItem(self): - """Check that an ImageData plot item can be used""" - dialog = self.colormapDiag - colormap = Colormap(name='gray', vmin=None, vmax=None) - data = numpy.arange(3**2).reshape(3, 3) - item = ImageData() - item.setData(data, copy=False) - - dialog.setColormap(colormap) - dialog.show() - self.qapp.processEvents() - dialog.setItem(item) - vrange = dialog._getFiniteColormapRange() - self.assertEqual(vrange, (0, 8)) - - def testItemDel(self): - """Check that the plot items are not hard linked to the dialog""" - dialog = self.colormapDiag - colormap = Colormap(name='gray', vmin=None, vmax=None) - data = numpy.arange(3**2).reshape(3, 3) - item = ImageData() - item.setData(data, copy=False) - - dialog.setColormap(colormap) - dialog.show() - self.qapp.processEvents() - dialog.setItem(item) - previousRange = dialog._getFiniteColormapRange() - del item - vrange = dialog._getFiniteColormapRange() - self.assertNotEqual(vrange, previousRange) - - def testDataDel(self): - """Check that the data are not hard linked to the dialog""" - dialog = self.colormapDiag - colormap = Colormap(name='gray', vmin=None, vmax=None) - data = numpy.arange(5) - - dialog.setColormap(colormap) - dialog.show() - self.qapp.processEvents() - dialog.setData(data) - previousRange = dialog._getFiniteColormapRange() - del data - vrange = dialog._getFiniteColormapRange() - self.assertNotEqual(vrange, previousRange) - - def testDeleteWhileExec(self): - colormapDiag = self.colormapDiag - self.colormapDiag = None - qt.QTimer.singleShot(1000, colormapDiag.deleteLater) - result = colormapDiag.exec() - self.assertEqual(result, 0) + + def getFirstNotPreferredColormap(): + cms = Colormap.getSupportedColormaps() + preferred = preferredColormaps() + for cm in cms: + if cm not in preferred: + return cm + return None + + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + colormapName = getFirstNotPreferredColormap() + assert colormapName is not None + colormap = Colormap(name=colormapName) + dialog.setColormap(colormap) + qapp.processEvents() + + cb = dialog._comboBoxColormap + assert cb.getCurrentName() == colormapName + cb.setCurrentIndex(0) + index = cb.findLutName(colormapName) + assert index != 0 # if 0 then the rest of the test has no sense + cb.setCurrentIndex(index) + assert cb.getCurrentName() == colormapName + + +def testColormapEditableMode(qWidgetFactory): + """Test that the colormapDialog is correctly updated when changing the + colormap editable status""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + colormap = Colormap(normalization="linear", vmin=1.0, vmax=10.0) + + dialog.setColormap(colormap) + + for editable in (True, False): + colormap.setEditable(editable) + assert dialog._comboBoxColormap.isEnabled() is editable + assert dialog._minValue.isEnabled() is editable + assert dialog._maxValue.isEnabled() is editable + assert dialog._comboBoxNormalization.isEnabled() is editable + + # Make sure the reset button is also set to enable when edition mode is + # False + dialog.setModal(False) + colormap.setEditable(True) + dialog._comboBoxNormalization.setCurrentIndex( + dialog._comboBoxNormalization.findData(Colormap.LOGARITHM) + ) + resetButton = dialog._buttonsNonModal.button(qt.QDialogButtonBox.Reset) + assert resetButton.isEnabled() + colormap.setEditable(False) + assert not (resetButton.isEnabled()) + + +def testImageData(qWidgetFactory): + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + data = numpy.random.rand(5, 5) + dialog.setData(data) + + +def testEmptyData(qWidgetFactory): + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + data = numpy.empty((10, 0)) + dialog.setData(data) + + +def testNoneData(qWidgetFactory): + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + data = numpy.random.rand(5, 5) + dialog.setData(data) + dialog.setData(None) + + +def testImageItem(qapp, qWidgetFactory): + """Check that an ImageData plot item can be used""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + colormap = Colormap(name="gray", vmin=None, vmax=None) + data = numpy.arange(3**2).reshape(3, 3) + item = ImageData() + item.setData(data, copy=False) + + dialog.setColormap(colormap) + qapp.processEvents() + + dialog.setItem(item) + vrange = dialog._getFiniteColormapRange() + assert vrange == (0, 8) + + +def testItemDel(qapp, qWidgetFactory): + """Check that the plot items are not hard linked to the dialog""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + colormap = Colormap(name="gray", vmin=None, vmax=None) + data = numpy.arange(3**2).reshape(3, 3) + item = ImageData() + item.setData(data, copy=False) + + dialog.setColormap(colormap) + dialog.show() + qapp.processEvents() + dialog.setItem(item) + previousRange = dialog._getFiniteColormapRange() + del item + vrange = dialog._getFiniteColormapRange() + assert vrange != previousRange + + +def testDataDel(qapp, qWidgetFactory): + """Check that the data are not hard linked to the dialog""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + colormap = Colormap(name="gray", vmin=None, vmax=None) + data = numpy.arange(5) + + dialog.setColormap(colormap) + qapp.processEvents() + + dialog.setData(data) + previousRange = dialog._getFiniteColormapRange() + del data + vrange = dialog._getFiniteColormapRange() + assert vrange != previousRange + + +def testDeleteWhileExec(qWidgetFactory): + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + qt.QTimer.singleShot(1000, dialog.deleteLater) + result = dialog.exec() + assert result == 0 + + +def testUpdateImageData(qapp, qWidgetFactory): + """Test that range/histogram takes into account item updates""" + dialog = qWidgetFactory(ColormapDialog.ColormapDialog) + + item = ImageData() + item.setColormap(Colormap()) + dialog.setItem(item) + dialog.setColormap(item.getColormap()) + qapp.processEvents() + + assert dialog._histoWidget.getFiniteRange() == (0, 1) + + item.setData([(1, 2), (3, 4)]) + + assert dialog._histoWidget.getFiniteRange() == (1, 4) diff --git a/src/silx/gui/dialog/test/test_datafiledialog.py b/src/silx/gui/dialog/test/test_datafiledialog.py index 32d75c2..887ff1c 100644 --- a/src/silx/gui/dialog/test/test_datafiledialog.py +++ b/src/silx/gui/dialog/test/test_datafiledialog.py @@ -28,7 +28,6 @@ __license__ = "MIT" __date__ = "08/03/2019" -import unittest import tempfile import numpy import shutil @@ -65,7 +64,7 @@ def setUpModule(): f["complex_image"] = data * 1j f["group/image"] = data f["nxdata/foo"] = 10 - f["nxdata"].attrs["NX_class"] = u"NXdata" + f["nxdata"].attrs["NX_class"] = "NXdata" f.close() directory = os.path.join(_tmpDirectory, "data") @@ -78,7 +77,7 @@ def setUpModule(): f["complex_image"] = data * 1j f["group/image"] = data f["nxdata/foo"] = 10 - f["nxdata"].attrs["NX_class"] = u"NXdata" + f["nxdata"].attrs["NX_class"] = "NXdata" f.close() filename = _tmpDirectory + "/badformat.h5" @@ -99,7 +98,6 @@ def tearDownModule(): class _UtilsMixin(object): - def createDialog(self): self._deleteDialog() self._dialog = self._createDialog() @@ -139,7 +137,6 @@ class _UtilsMixin(object): class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): - def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) @@ -219,7 +216,11 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -249,7 +250,11 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -276,12 +281,16 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path() dialog.selectUrl(path) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/image" + ).path() self.assertSamePath(url.text(), path) # test self.mouseClick(toParentButton, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() self.assertSamePath(url.text(), path) self.mouseClick(toParentButton, qt.Qt.LeftButton) @@ -303,7 +312,9 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): filename = _tmpDirectory + "/data.h5" # init state - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/image" + ).path() dialog.selectUrl(path) self.qWaitForPendingActions(dialog) self.assertSamePath(url.text(), path) @@ -311,7 +322,9 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # test self.mouseClick(button, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() self.assertSamePath(url.text(), path) # self.assertFalse(button.isEnabled()) @@ -329,7 +342,9 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path() dialog.selectUrl(path) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/image" + ).path() self.assertSamePath(url.text(), path) self.assertTrue(button.isEnabled()) # test @@ -348,8 +363,12 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForWindowExposed(dialog) url = testutils.findChildren(dialog, qt.QLineEdit, name="url")[0] - forwardAction = testutils.findChildren(dialog, qt.QAction, name="forwardAction")[0] - backwardAction = testutils.findChildren(dialog, qt.QAction, name="backwardAction")[0] + forwardAction = testutils.findChildren( + dialog, qt.QAction, name="forwardAction" + )[0] + backwardAction = testutils.findChildren( + dialog, qt.QAction, name="backwardAction" + )[0] filename = _tmpDirectory + "/data.h5" dialog.setDirectory(_tmpDirectory) @@ -358,10 +377,14 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # Then we feed the history using selectPath dialog.selectUrl(filename) self.qWaitForPendingActions(dialog) - path2 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path2 = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() dialog.selectUrl(path2) self.qWaitForPendingActions(dialog) - path3 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group").path() + path3 = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group" + ).path() dialog.selectUrl(path3) self.qWaitForPendingActions(dialog) self.assertFalse(forwardAction.isEnabled()) @@ -388,7 +411,11 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # init state filename = _tmpDirectory + "/singleimage.edf" - url = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/scan_0/instrument/detector_0/data") + url = silx.io.url.DataUrl( + scheme="silx", + file_path=filename, + data_path="/scan_0/instrument/detector_0/data", + ) dialog.selectUrl(url.path()) self.assertEqual(dialog._selectedData().shape, (100, 100)) self.assertSamePath(dialog.selectedFile(), filename) @@ -401,7 +428,9 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # init state filename = _tmpDirectory + "/data.h5" - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/image" + ).path() dialog.selectUrl(path) # test self.assertEqual(dialog._selectedData().shape, (100, 100)) @@ -415,7 +444,9 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # init state filename = _tmpDirectory + "/data.h5" - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/scalar").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/scalar" + ).path() dialog.selectUrl(path) # test self.assertEqual(dialog._selectedData()[()], 10) @@ -464,7 +495,9 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] filename = _tmpDirectory + "/data.h5" - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() index = browser.rootIndex().model().index(filename) # click browser.selectIndex(index) @@ -508,11 +541,12 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForWindowExposed(dialog) dialog.selectUrl(_tmpDirectory) self.qWaitForPendingActions(dialog) - self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 4) + self.assertEqual( + self._countSelectableItems(browser.model(), browser.rootIndex()), 4 + ) class TestDataFileDialog_FilterDataset(testutils.TestCaseQt, _UtilsMixin): - def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) @@ -539,7 +573,11 @@ class TestDataFileDialog_FilterDataset(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -564,7 +602,11 @@ class TestDataFileDialog_FilterDataset(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -582,7 +624,6 @@ class TestDataFileDialog_FilterDataset(testutils.TestCaseQt, _UtilsMixin): class TestDataFileDialog_FilterGroup(testutils.TestCaseQt, _UtilsMixin): - def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) @@ -609,7 +650,11 @@ class TestDataFileDialog_FilterGroup(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -641,7 +686,11 @@ class TestDataFileDialog_FilterGroup(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -651,7 +700,6 @@ class TestDataFileDialog_FilterGroup(testutils.TestCaseQt, _UtilsMixin): class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): - def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) @@ -659,7 +707,7 @@ class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): def _createDialog(self): def customFilter(obj): if "NX_class" in obj.attrs: - return obj.attrs["NX_class"] == u"NXdata" + return obj.attrs["NX_class"] == "NXdata" return False dialog = DataFileDialog() @@ -684,7 +732,11 @@ class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -711,7 +763,11 @@ class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) # select, then double click on the file - index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/nxdata"]) + index = ( + browser.rootIndex() + .model() + .indexFromH5Object(dialog._AbstractDataFileDialog__h5["/nxdata"]) + ) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) @@ -726,7 +782,6 @@ class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): class TestDataFileDialogApi(testutils.TestCaseQt, _UtilsMixin): - def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) @@ -779,46 +834,50 @@ class TestDataFileDialogApi(testutils.TestCaseQt, _UtilsMixin): print() print("\\\n".join(strings)) - STATE_VERSION1_QT4 = b''\ - b'\x00\x00\x00Z\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\ - b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00a\x00F\x00i'\ - b'\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00'\ - b'a\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00\x00\x00'\ - b'\x01\x00\x00\x00\x0C\x00\x00\x00\x00"\x00\x00\x00\xFF\x00\x00'\ - b'\x00\x00\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\ - b'\xFF\xFF\x01\x00\x00\x00\x06\x01\x00\x00\x00\x01\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x00'\ - b'}\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00r\x00\x00\x00'\ - b'\x01\x00\x00\x00\x0C\x00\x00\x00\x00Z\x00\x00\x00\xFF\x00\x00'\ - b'\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ - b'\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00\x00\x00\x81'\ - b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x01\x90\x00\x00\x00\x04'\ - b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00'\ - b'\x01\xFF\xFF\xFF\xFF' + STATE_VERSION1_QT4 = ( + b"" + b"\x00\x00\x00Z\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00" + b"d\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00a\x00F\x00i" + b"\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00" + b"a\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00\x00\x00" + b'\x01\x00\x00\x00\x0C\x00\x00\x00\x00"\x00\x00\x00\xFF\x00\x00' + b"\x00\x00\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + b"\xFF\xFF\x01\x00\x00\x00\x06\x01\x00\x00\x00\x01\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00\x00" + b"}\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00r\x00\x00\x00" + b"\x01\x00\x00\x00\x0C\x00\x00\x00\x00Z\x00\x00\x00\xFF\x00\x00" + b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00\x00\x00\x81" + b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x01\x90\x00\x00\x00\x04" + b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00" + b"\x01\xFF\xFF\xFF\xFF" + ) """Serialized state on Qt4. Generated using :meth:`printState`""" - STATE_VERSION1_QT5 = b''\ - b'\x00\x00\x00Z\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\ - b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00a\x00F\x00i'\ - b'\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00'\ - b'a\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00\x00\x00'\ - b'\x01\x00\x00\x00\x0C\x00\x00\x00\x00#\x00\x00\x00\xFF\x00\x00'\ - b'\x00\x01\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\ - b'\xFF\xFF\x01\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x01\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00'\ - b'\x00\xAA\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00r\x00'\ - b'\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00\x87\x00\x00\x00\xFF'\ - b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00'\ - b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ - b'\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00\x00'\ - b'\x00\x81\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00d\x00\x00'\ - b'\x00\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00'\ - b'\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00'\ - b'\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03\xE8\x00\xFF'\ - b'\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x01' + STATE_VERSION1_QT5 = ( + b"" + b"\x00\x00\x00Z\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00" + b"d\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00a\x00F\x00i" + b"\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00D\x00a\x00t\x00" + b"a\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00\x00\x00" + b"\x01\x00\x00\x00\x0C\x00\x00\x00\x00#\x00\x00\x00\xFF\x00\x00" + b"\x00\x01\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + b"\xFF\xFF\x01\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x01\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00\x00\x00" + b"\x00\xAA\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00r\x00" + b"\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00\x87\x00\x00\x00\xFF" + b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00\x00" + b"\x00\x81\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00d\x00\x00" + b"\x00\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00" + b"\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00" + b"\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03\xE8\x00\xFF" + b"\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x01" + ) """Serialized state on Qt5. Generated using :meth:`printState`""" def testAvoidRestoreRegression_Version1(self): @@ -903,7 +962,9 @@ class TestDataFileDialogApi(testutils.TestCaseQt, _UtilsMixin): browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] filename = _tmpDirectory + "/data.h5" - url = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/foobar") + url = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/foobar" + ) dialog.selectUrl(url.path()) self.qWaitForPendingActions(dialog) self.assertIsNotNone(dialog._selectedData()) diff --git a/src/silx/gui/dialog/test/test_imagefiledialog.py b/src/silx/gui/dialog/test/test_imagefiledialog.py index 79c12ed..9d2c414 100644 --- a/src/silx/gui/dialog/test/test_imagefiledialog.py +++ b/src/silx/gui/dialog/test/test_imagefiledialog.py @@ -28,7 +28,6 @@ __license__ = "MIT" __date__ = "08/03/2019" -import unittest import tempfile import numpy import shutil @@ -106,7 +105,6 @@ def tearDownModule(): class _UtilsMixin(object): - def createDialog(self): self._deleteDialog() self._dialog = self._createDialog() @@ -146,7 +144,6 @@ class _UtilsMixin(object): class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): - def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) @@ -201,6 +198,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.assertEqual(dialog.result(), qt.QDialog.Accepted) def testClickOnShortcut(self): + if qt.BINDING == "PySide6": + self.skipTest("Avoid segmentation fault with PySide6") + dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) @@ -264,12 +264,16 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path() dialog.selectUrl(path) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/image" + ).path() self.assertSamePath(url.text(), path) # test self.mouseClick(toParentButton, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() self.assertSamePath(url.text(), path) self.mouseClick(toParentButton, qt.Qt.LeftButton) @@ -291,7 +295,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): filename = _tmpDirectory + "/data.h5" # init state - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/image" + ).path() dialog.selectUrl(path) self.qWaitForPendingActions(dialog) self.assertSamePath(url.text(), path) @@ -299,7 +305,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # test self.mouseClick(button, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() self.assertSamePath(url.text(), path) # self.assertFalse(button.isEnabled()) @@ -317,7 +325,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): path = silx.io.url.DataUrl(file_path=filename, data_path="/group/image").path() dialog.selectUrl(path) self.qWaitForPendingActions(dialog) - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/image" + ).path() self.assertSamePath(url.text(), path) self.assertTrue(button.isEnabled()) # test @@ -336,8 +346,12 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForWindowExposed(dialog) url = testutils.findChildren(dialog, qt.QLineEdit, name="url")[0] - forwardAction = testutils.findChildren(dialog, qt.QAction, name="forwardAction")[0] - backwardAction = testutils.findChildren(dialog, qt.QAction, name="backwardAction")[0] + forwardAction = testutils.findChildren( + dialog, qt.QAction, name="forwardAction" + )[0] + backwardAction = testutils.findChildren( + dialog, qt.QAction, name="backwardAction" + )[0] filename = _tmpDirectory + "/data.h5" dialog.setDirectory(_tmpDirectory) @@ -346,10 +360,14 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # Then we feed the history using selectPath dialog.selectUrl(filename) self.qWaitForPendingActions(dialog) - path2 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path2 = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() dialog.selectUrl(path2) self.qWaitForPendingActions(dialog) - path3 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group").path() + path3 = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group" + ).path() dialog.selectUrl(path3) self.qWaitForPendingActions(dialog) self.assertFalse(forwardAction.isEnabled()) @@ -412,7 +430,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # init state filename = _tmpDirectory + "/multiframe.edf" - path = silx.io.url.DataUrl(scheme="fabio", file_path=filename, data_slice=(1,)).path() + path = silx.io.url.DataUrl( + scheme="fabio", file_path=filename, data_slice=(1,) + ).path() dialog.selectUrl(path) # test image = dialog.selectedImage() @@ -442,7 +462,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # init state filename = _tmpDirectory + "/data.h5" - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/image").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/image" + ).path() dialog.selectUrl(path) # test self.assertEqual(dialog.selectedImage().shape, (100, 100)) @@ -459,7 +481,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForPendingActions(dialog) browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] filename = _tmpDirectory + "/data.h5" - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/" + ).path() index = browser.rootIndex().model().index(filename) # click browser.selectIndex(index) @@ -476,7 +500,9 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # init state filename = _tmpDirectory + "/data.h5" - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/cube", data_slice=(1, )).path() + path = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/cube", data_slice=(1,) + ).path() dialog.selectUrl(path) # test self.assertEqual(dialog.selectedImage().shape, (100, 100)) @@ -491,7 +517,12 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): # init state filename = _tmpDirectory + "/data.h5" - path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/single_frame", data_slice=(0, )).path() + path = silx.io.url.DataUrl( + scheme="silx", + file_path=filename, + data_path="/single_frame", + data_slice=(0,), + ).path() dialog.selectUrl(path) # test self.assertEqual(dialog.selectedImage().shape, (100, 100)) @@ -534,25 +565,30 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): self.qWaitForWindowExposed(dialog) dialog.selectUrl(_tmpDirectory) self.qWaitForPendingActions(dialog) - self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 6) + self.assertEqual( + self._countSelectableItems(browser.model(), browser.rootIndex()), 6 + ) codecName = fabio.edfimage.EdfImage.codec_name() index = filters.indexFromCodec(codecName) filters.setCurrentIndex(index) filters.activated[int].emit(index) self.qWait(50) - self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 4) + self.assertEqual( + self._countSelectableItems(browser.model(), browser.rootIndex()), 4 + ) codecName = fabio.fit2dmaskimage.Fit2dMaskImage.codec_name() index = filters.indexFromCodec(codecName) filters.setCurrentIndex(index) filters.activated[int].emit(index) self.qWait(50) - self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 2) + self.assertEqual( + self._countSelectableItems(browser.model(), browser.rootIndex()), 2 + ) class TestImageFileDialogApi(testutils.TestCaseQt, _UtilsMixin): - def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) @@ -606,51 +642,55 @@ class TestImageFileDialogApi(testutils.TestCaseQt, _UtilsMixin): print() print("\\\n".join(strings)) - STATE_VERSION1_QT4 = b''\ - b'\x00\x00\x00^\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\ - b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00a\x00g\x00e\x00F'\ - b'\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00'\ - b'a\x00g\x00e\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g'\ - b'\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00"\x00\x00\x00'\ - b'\xFF\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\ - b'\xFF\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x06\x01\x00\x00\x00\x01\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00'\ - b'\x00\x00\x00}\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00'\ - b'r\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00Z\x00\x00\x00'\ - b'\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'\ - b'\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00'\ - b'\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x01\x90\x00'\ - b'\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00'\ - b'\x00\x00\x0C\x00\x00\x00\x000\x00\x00\x00\x10\x00C\x00o\x00l\x00'\ - b'o\x00r\x00m\x00a\x00p\x00\x00\x00\x01\x00\x00\x00\x08\x00g\x00'\ - b'r\x00a\x00y\x01\x01\x00\x00\x00\x06\x00l\x00o\x00g' + STATE_VERSION1_QT4 = ( + b"" + b"\x00\x00\x00^\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00" + b"d\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00a\x00g\x00e\x00F" + b"\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00" + b"a\x00g\x00e\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g" + b'\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00"\x00\x00\x00' + b"\xFF\x00\x00\x00\x00\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + b"\xFF\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x06\x01\x00\x00\x00\x01\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\x00" + b"\x00\x00\x00}\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s\x00e\x00" + b"r\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00Z\x00\x00\x00" + b"\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF\xFF\xFF\x00" + b"\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x01\x90\x00" + b"\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00" + b"\x00\x00\x0C\x00\x00\x00\x000\x00\x00\x00\x10\x00C\x00o\x00l\x00" + b"o\x00r\x00m\x00a\x00p\x00\x00\x00\x01\x00\x00\x00\x08\x00g\x00" + b"r\x00a\x00y\x01\x01\x00\x00\x00\x06\x00l\x00o\x00g" + ) """Serialized state on Qt4. Generated using :meth:`printState`""" - STATE_VERSION1_QT5 = b''\ - b'\x00\x00\x00^\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00'\ - b'd\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00a\x00g\x00e\x00F'\ - b'\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00'\ - b'a\x00g\x00e\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g'\ - b'\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00#\x00\x00\x00'\ - b'\xFF\x00\x00\x00\x01\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF'\ - b'\xFF\xFF\xFF\xFF\xFF\x01\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x01\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C'\ - b'\x00\x00\x00\x00\xAA\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s'\ - b'\x00e\x00r\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00\x87'\ - b'\x00\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00'\ - b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF'\ - b'\xFF\xFF\x00\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00'\ - b'\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00'\ - b'\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00'\ - b'\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03'\ - b'\xE8\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00'\ - b'\x00\x0C\x00\x00\x00\x000\x00\x00\x00\x10\x00C\x00o\x00l\x00o'\ - b'\x00r\x00m\x00a\x00p\x00\x00\x00\x01\x00\x00\x00\x08\x00g\x00'\ - b'r\x00a\x00y\x01\x01\x00\x00\x00\x06\x00l\x00o\x00g' + STATE_VERSION1_QT5 = ( + b"" + b"\x00\x00\x00^\x00s\x00i\x00l\x00x\x00.\x00g\x00u\x00i\x00.\x00" + b"d\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00a\x00g\x00e\x00F" + b"\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g\x00.\x00I\x00m\x00" + b"a\x00g\x00e\x00F\x00i\x00l\x00e\x00D\x00i\x00a\x00l\x00o\x00g" + b"\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00#\x00\x00\x00" + b"\xFF\x00\x00\x00\x01\x00\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + b"\xFF\xFF\xFF\xFF\xFF\x01\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x01\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C" + b"\x00\x00\x00\x00\xAA\x00\x00\x00\x0E\x00B\x00r\x00o\x00w\x00s" + b"\x00e\x00r\x00\x00\x00\x01\x00\x00\x00\x0C\x00\x00\x00\x00\x87" + b"\x00\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x01\x90\x00\x00\x00\x04\x01\x01\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xFF\xFF" + b"\xFF\xFF\x00\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00" + b"\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00" + b"\x01\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00" + b"\x00\x00\x00\x00d\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03" + b"\xE8\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00" + b"\x00\x0C\x00\x00\x00\x000\x00\x00\x00\x10\x00C\x00o\x00l\x00o" + b"\x00r\x00m\x00a\x00p\x00\x00\x00\x01\x00\x00\x00\x08\x00g\x00" + b"r\x00a\x00y\x01\x01\x00\x00\x00\x06\x00l\x00o\x00g" + ) """Serialized state on Qt5. Generated using :meth:`printState`""" def testAvoidRestoreRegression_Version1(self): @@ -757,7 +797,9 @@ class TestImageFileDialogApi(testutils.TestCaseQt, _UtilsMixin): browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] filename = _tmpDirectory + "/data.h5" - url = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group/foobar") + url = silx.io.url.DataUrl( + scheme="silx", file_path=filename, data_path="/group/foobar" + ) dialog.selectUrl(url.path()) self.qWaitForPendingActions(dialog) self.assertIsNone(dialog._selectedData()) diff --git a/src/silx/gui/dialog/utils.py b/src/silx/gui/dialog/utils.py index e07cf9f..1697bcf 100644 --- a/src/silx/gui/dialog/utils.py +++ b/src/silx/gui/dialog/utils.py @@ -85,7 +85,7 @@ def patchToConsumeReturnKey(widget): Monkey-patch a widget to consume the return key instead of propagating it to the dialog. """ - assert(not hasattr(widget, "_oldKeyPressEvent")) + assert not hasattr(widget, "_oldKeyPressEvent") def keyPressEvent(self, event): k = event.key() |