# coding: utf-8 # /*########################################################################## # # Copyright (c) 2016 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 # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # ###########################################################################*/ """Test for silx.gui.hdf5 module""" __authors__ = ["V. Valls"] __license__ = "MIT" __date__ = "05/10/2018" import unittest import tempfile import numpy import shutil import os import io import weakref try: import fabio except ImportError: fabio = None try: import h5py except ImportError: h5py = None import silx.io.url from silx.gui import qt from silx.gui.utils import testutils from ..DataFileDialog import DataFileDialog from silx.gui.hdf5 import Hdf5TreeModel _tmpDirectory = None def setUpModule(): global _tmpDirectory _tmpDirectory = tempfile.mkdtemp(prefix=__name__) data = numpy.arange(100 * 100) data.shape = 100, 100 if fabio is not None: filename = _tmpDirectory + "/singleimage.edf" image = fabio.edfimage.EdfImage(data=data) image.write(filename) if h5py is not None: filename = _tmpDirectory + "/data.h5" f = h5py.File(filename, "w") f["scalar"] = 10 f["image"] = data f["cube"] = [data, data + 1, data + 2] f["complex_image"] = data * 1j f["group/image"] = data f["nxdata/foo"] = 10 f["nxdata"].attrs["NX_class"] = u"NXdata" f.close() if h5py is not None: directory = os.path.join(_tmpDirectory, "data") os.mkdir(directory) filename = os.path.join(directory, "data.h5") f = h5py.File(filename, "w") f["scalar"] = 10 f["image"] = data f["cube"] = [data, data + 1, data + 2] f["complex_image"] = data * 1j f["group/image"] = data f["nxdata/foo"] = 10 f["nxdata"].attrs["NX_class"] = u"NXdata" f.close() filename = _tmpDirectory + "/badformat.h5" with io.open(filename, "wb") as f: f.write(b"{\nHello Nurse!") def tearDownModule(): global _tmpDirectory shutil.rmtree(_tmpDirectory) _tmpDirectory = None class _UtilsMixin(object): def createDialog(self): self._deleteDialog() self._dialog = self._createDialog() return self._dialog def _createDialog(self): return DataFileDialog() def _deleteDialog(self): if not hasattr(self, "_dialog"): return if self._dialog is not None: ref = weakref.ref(self._dialog) self._dialog = None self.qWaitForDestroy(ref) def qWaitForPendingActions(self, dialog): for _ in range(20): if not dialog.hasPendingEvents(): return self.qWait(10) raise RuntimeError("Still have pending actions") def assertSamePath(self, path1, path2): path1_ = os.path.normcase(path1) path2_ = os.path.normcase(path2) if path1_ != path2_: # Use the unittest API to log and display error self.assertEqual(path1, path2) def assertNotSamePath(self, path1, path2): path1_ = os.path.normcase(path1) path2_ = os.path.normcase(path2) if path1_ == path2_: # Use the unittest API to log and display error self.assertNotEquals(path1, path2) class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin): def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) def testDisplayAndKeyEscape(self): dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) self.keyClick(dialog, qt.Qt.Key_Escape) self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Rejected) def testDisplayAndClickCancel(self): dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) button = testutils.findChildren(dialog, qt.QPushButton, name="cancel")[0] self.mouseClick(button, qt.Qt.LeftButton) self.assertFalse(dialog.isVisible()) self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Rejected) def testDisplayAndClickLockedOpen(self): dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.mouseClick(button, qt.Qt.LeftButton) # open button locked, dialog is not closed self.assertTrue(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Rejected) def testSelectRoot_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertTrue(button.isEnabled()) self.mouseClick(button, qt.Qt.LeftButton) url = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertTrue(url.data_path() is not None) self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Accepted) def testSelectGroup_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertTrue(button.isEnabled()) self.mouseClick(button, qt.Qt.LeftButton) url = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertEqual(url.data_path(), "/group") self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Accepted) def testSelectDataset_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertTrue(button.isEnabled()) self.mouseClick(button, qt.Qt.LeftButton) url = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertEqual(url.data_path(), "/scalar") self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Accepted) def testClickOnBackToParentTool(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) url = testutils.findChildren(dialog, qt.QLineEdit, name="url")[0] action = testutils.findChildren(dialog, qt.QAction, name="toParentAction")[0] toParentButton = testutils.getQToolButtonFromAction(action) filename = _tmpDirectory + "/data/data.h5" # init state 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() 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() self.assertSamePath(url.text(), path) self.mouseClick(toParentButton, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) self.assertSamePath(url.text(), _tmpDirectory + "/data") self.mouseClick(toParentButton, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) self.assertSamePath(url.text(), _tmpDirectory) def testClickOnBackToRootTool(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) url = testutils.findChildren(dialog, qt.QLineEdit, name="url")[0] action = testutils.findChildren(dialog, qt.QAction, name="toRootFileAction")[0] button = testutils.getQToolButtonFromAction(action) filename = _tmpDirectory + "/data.h5" # init state 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) self.assertTrue(button.isEnabled()) # test self.mouseClick(button, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/").path() self.assertSamePath(url.text(), path) # self.assertFalse(button.isEnabled()) def testClickOnBackToDirectoryTool(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) url = testutils.findChildren(dialog, qt.QLineEdit, name="url")[0] action = testutils.findChildren(dialog, qt.QAction, name="toDirectoryAction")[0] button = testutils.getQToolButtonFromAction(action) filename = _tmpDirectory + "/data.h5" # init state 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() self.assertSamePath(url.text(), path) self.assertTrue(button.isEnabled()) # test self.mouseClick(button, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) self.assertSamePath(url.text(), _tmpDirectory) self.assertFalse(button.isEnabled()) # FIXME: There is an unreleased qt.QWidget without nameObject # No idea where it come from. self.allowedLeakingWidgets = 1 def testClickOnHistoryTools(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() 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] filename = _tmpDirectory + "/data.h5" dialog.setDirectory(_tmpDirectory) self.qWaitForPendingActions(dialog) # No way to use QTest.mouseDClick with QListView, QListWidget # 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() dialog.selectUrl(path2) self.qWaitForPendingActions(dialog) path3 = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group").path() dialog.selectUrl(path3) self.qWaitForPendingActions(dialog) self.assertFalse(forwardAction.isEnabled()) self.assertTrue(backwardAction.isEnabled()) button = testutils.getQToolButtonFromAction(backwardAction) self.mouseClick(button, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) self.assertTrue(forwardAction.isEnabled()) self.assertTrue(backwardAction.isEnabled()) self.assertSamePath(url.text(), path2) button = testutils.getQToolButtonFromAction(forwardAction) self.mouseClick(button, qt.Qt.LeftButton) self.qWaitForPendingActions(dialog) self.assertFalse(forwardAction.isEnabled()) self.assertTrue(backwardAction.isEnabled()) self.assertSamePath(url.text(), path3) def testSelectImageFromEdf(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) # init state filename = _tmpDirectory + "/singleimage.edf" url = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/scan_0/instrument/detector_0/data") dialog.selectUrl(url.path()) self.assertTrue(dialog._selectedData().shape, (100, 100)) self.assertSamePath(dialog.selectedFile(), filename) self.assertSamePath(dialog.selectedUrl(), url.path()) def testSelectImage(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) # init state filename = _tmpDirectory + "/data.h5" path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/image").path() dialog.selectUrl(path) # test self.assertTrue(dialog._selectedData().shape, (100, 100)) self.assertSamePath(dialog.selectedFile(), filename) self.assertSamePath(dialog.selectedUrl(), path) def testSelectScalar(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) # init state filename = _tmpDirectory + "/data.h5" path = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/scalar").path() dialog.selectUrl(path) # test self.assertEqual(dialog._selectedData()[()], 10) self.assertSamePath(dialog.selectedFile(), filename) self.assertSamePath(dialog.selectedUrl(), path) def testSelectGroup(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) # init state filename = _tmpDirectory + "/data.h5" uri = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/group") dialog.selectUrl(uri.path()) self.qWaitForPendingActions(dialog) # test self.assertTrue(silx.io.is_group(dialog._selectedData())) self.assertSamePath(dialog.selectedFile(), filename) uri = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertSamePath(uri.data_path(), "/group") def testSelectRoot(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) # init state filename = _tmpDirectory + "/data.h5" uri = silx.io.url.DataUrl(scheme="silx", file_path=filename, data_path="/") dialog.selectUrl(uri.path()) self.qWaitForPendingActions(dialog) # test self.assertTrue(silx.io.is_file(dialog._selectedData())) self.assertSamePath(dialog.selectedFile(), filename) uri = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertSamePath(uri.data_path(), "/") def testSelectH5_Activate(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) # init state dialog.selectUrl(_tmpDirectory) 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() index = browser.rootIndex().model().index(filename) # click browser.selectIndex(index) # double click browser.activated.emit(index) self.qWaitForPendingActions(dialog) # test self.assertSamePath(dialog.selectedUrl(), path) def testSelectBadFileFormat_Activate(self): dialog = self.createDialog() dialog.show() self.qWaitForWindowExposed(dialog) # init state dialog.selectUrl(_tmpDirectory) self.qWaitForPendingActions(dialog) browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] filename = _tmpDirectory + "/badformat.h5" index = browser.rootIndex().model().index(filename) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # test self.assertTrue(dialog.selectedUrl(), filename) def _countSelectableItems(self, model, rootIndex): selectable = 0 for i in range(model.rowCount(rootIndex)): index = model.index(i, 0, rootIndex) flags = model.flags(index) isEnabled = (int(flags) & qt.Qt.ItemIsEnabled) != 0 if isEnabled: selectable += 1 return selectable def testFilterExtensions(self): if h5py is None: self.skipTest("h5py is missing") if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) dialog.selectUrl(_tmpDirectory) self.qWaitForPendingActions(dialog) self.assertEqual(self._countSelectableItems(browser.model(), browser.rootIndex()), 4) class TestDataFileDialog_FilterDataset(testutils.TestCaseQt, _UtilsMixin): def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) def _createDialog(self): dialog = DataFileDialog() dialog.setFilterMode(DataFileDialog.FilterMode.ExistingDataset) return dialog def testSelectGroup_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertFalse(button.isEnabled()) def testSelectDataset_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertTrue(button.isEnabled()) self.mouseClick(button, qt.Qt.LeftButton) url = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertEqual(url.data_path(), "/scalar") self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Accepted) data = dialog.selectedData() self.assertEqual(data, 10) class TestDataFileDialog_FilterGroup(testutils.TestCaseQt, _UtilsMixin): def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) def _createDialog(self): dialog = DataFileDialog() dialog.setFilterMode(DataFileDialog.FilterMode.ExistingGroup) return dialog def testSelectGroup_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertTrue(button.isEnabled()) self.mouseClick(button, qt.Qt.LeftButton) url = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertEqual(url.data_path(), "/group") self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Accepted) self.assertRaises(Exception, dialog.selectedData) def testSelectDataset_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/scalar"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertFalse(button.isEnabled()) class TestDataFileDialog_FilterNXdata(testutils.TestCaseQt, _UtilsMixin): def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) def _createDialog(self): def customFilter(obj): if "NX_class" in obj.attrs: return obj.attrs["NX_class"] == u"NXdata" return False dialog = DataFileDialog() dialog.setFilterMode(DataFileDialog.FilterMode.ExistingGroup) dialog.setFilterCallback(customFilter) return dialog def testSelectGroupRefused_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/group"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertFalse(button.isEnabled()) self.assertRaises(Exception, dialog.selectedData) def testSelectNXdataAccepted_Activate(self): if fabio is None: self.skipTest("fabio is missing") dialog = self.createDialog() browser = testutils.findChildren(dialog, qt.QWidget, name="browser")[0] dialog.show() self.qWaitForWindowExposed(dialog) self.assertTrue(dialog.isVisible()) filename = _tmpDirectory + "/data.h5" dialog.selectFile(os.path.dirname(filename)) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().index(filename) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) # select, then double click on the file index = browser.rootIndex().model().indexFromH5Object(dialog._AbstractDataFileDialog__h5["/nxdata"]) browser.selectIndex(index) browser.activated.emit(index) self.qWaitForPendingActions(dialog) button = testutils.findChildren(dialog, qt.QPushButton, name="open")[0] self.assertTrue(button.isEnabled()) self.mouseClick(button, qt.Qt.LeftButton) url = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertEqual(url.data_path(), "/nxdata") self.assertFalse(dialog.isVisible()) self.assertEqual(dialog.result(), qt.QDialog.Accepted) class TestDataFileDialogApi(testutils.TestCaseQt, _UtilsMixin): def tearDown(self): self._deleteDialog() testutils.TestCaseQt.tearDown(self) def _createDialog(self): dialog = DataFileDialog() return dialog def testSaveRestoreState(self): dialog = self.createDialog() dialog.setDirectory(_tmpDirectory) self.qWaitForPendingActions(dialog) state = dialog.saveState() dialog = None dialog2 = self.createDialog() result = dialog2.restoreState(state) self.assertTrue(result) dialog2 = None def printState(self): """ Print state of the ImageFileDialog. Can be used to add or regenerate `STATE_VERSION1_QT4` or `STATE_VERSION1_QT5`. >>> ./run_tests.py -v silx.gui.dialog.test.test_datafiledialog.TestDataFileDialogApi.printState """ dialog = self.createDialog() dialog.setDirectory("") dialog.setHistory([]) dialog.setSidebarUrls([]) state = dialog.saveState() string = "" strings = [] for i in range(state.size()): d = state.data()[i] if not isinstance(d, int): d = ord(d) if d > 0x20 and d < 0x7F: string += chr(d) else: string += "\\x%02X" % d if len(string) > 60: strings.append(string) string = "" strings.append(string) strings = ["b'%s'" % s for s in strings] 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' """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' """Serialized state on Qt5. Generated using :meth:`printState`""" def testAvoidRestoreRegression_Version1(self): version = qt.qVersion().split(".")[0] if version == "4": state = self.STATE_VERSION1_QT4 elif version == "5": state = self.STATE_VERSION1_QT5 else: self.skipTest("Resource not available") state = qt.QByteArray(state) dialog = self.createDialog() result = dialog.restoreState(state) self.assertTrue(result) def testRestoreRobusness(self): """What's happen if you try to open a config file with a different binding.""" state = qt.QByteArray(self.STATE_VERSION1_QT4) dialog = self.createDialog() dialog.restoreState(state) state = qt.QByteArray(self.STATE_VERSION1_QT5) dialog = None dialog = self.createDialog() dialog.restoreState(state) def testRestoreNonExistingDirectory(self): directory = os.path.join(_tmpDirectory, "dir") os.mkdir(directory) dialog = self.createDialog() dialog.setDirectory(directory) self.qWaitForPendingActions(dialog) state = dialog.saveState() os.rmdir(directory) dialog = None dialog2 = self.createDialog() result = dialog2.restoreState(state) self.assertTrue(result) self.assertNotEquals(dialog2.directory(), directory) def testHistory(self): dialog = self.createDialog() history = dialog.history() dialog.setHistory([]) self.assertEqual(dialog.history(), []) dialog.setHistory(history) self.assertEqual(dialog.history(), history) def testSidebarUrls(self): dialog = self.createDialog() urls = dialog.sidebarUrls() dialog.setSidebarUrls([]) self.assertEqual(dialog.sidebarUrls(), []) dialog.setSidebarUrls(urls) self.assertEqual(dialog.sidebarUrls(), urls) def testDirectory(self): dialog = self.createDialog() self.qWaitForPendingActions(dialog) dialog.selectUrl(_tmpDirectory) self.qWaitForPendingActions(dialog) self.assertSamePath(dialog.directory(), _tmpDirectory) def testBadFileFormat(self): dialog = self.createDialog() dialog.selectUrl(_tmpDirectory + "/badformat.h5") self.qWaitForPendingActions(dialog) self.assertIsNone(dialog._selectedData()) def testBadPath(self): dialog = self.createDialog() dialog.selectUrl("#$%/#$%") self.qWaitForPendingActions(dialog) self.assertIsNone(dialog._selectedData()) def testBadSubpath(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() self.qWaitForPendingActions(dialog) 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") dialog.selectUrl(url.path()) self.qWaitForPendingActions(dialog) self.assertIsNotNone(dialog._selectedData()) # an existing node is browsed, but the wrong path is selected index = browser.rootIndex() obj = index.model().data(index, role=Hdf5TreeModel.H5PY_OBJECT_ROLE) self.assertEqual(obj.name, "/group") url = silx.io.url.DataUrl(dialog.selectedUrl()) self.assertEqual(url.data_path(), "/group") def testUnsupportedSlicingPath(self): if h5py is None: self.skipTest("h5py is missing") dialog = self.createDialog() self.qWaitForPendingActions(dialog) dialog.selectUrl(_tmpDirectory + "/data.h5?path=/cube&slice=0") self.qWaitForPendingActions(dialog) data = dialog._selectedData() if data is None: # Maybe nothing is selected self.assertTrue(True) else: # Maybe the cube is selected but not sliced self.assertEqual(len(data.shape), 3) def suite(): test_suite = unittest.TestSuite() loadTests = unittest.defaultTestLoader.loadTestsFromTestCase test_suite.addTest(loadTests(TestDataFileDialogInteraction)) test_suite.addTest(loadTests(TestDataFileDialogApi)) test_suite.addTest(loadTests(TestDataFileDialog_FilterDataset)) test_suite.addTest(loadTests(TestDataFileDialog_FilterGroup)) test_suite.addTest(loadTests(TestDataFileDialog_FilterNXdata)) return test_suite if __name__ == '__main__': unittest.main(defaultTest='suite')