tomwer 1.2.0a1__py3-none-any.whl → 1.2.0a3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orangecontrib/tomwer/tutorials/append_raw_darks_and_flats_frames_to_NXtomos.ows +44 -0
- orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth1.ows +55 -0
- orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth2.ows +48 -0
- orangecontrib/tomwer/tutorials/default_cor_search.ows +40 -0
- orangecontrib/tomwer/tutorials/hello_world_python_script.ows +50 -0
- orangecontrib/tomwer/tutorials/simple_slice_reconstruction_on_slurm.ows +50 -0
- orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +8 -8
- orangecontrib/tomwer/widgets/__init__.py +1 -1
- orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +0 -1
- orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +8 -6
- orangecontrib/tomwer/widgets/control/AdvancementOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +1 -6
- orangecontrib/tomwer/widgets/control/DataListOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataListenerOW.py +4 -4
- orangecontrib/tomwer/widgets/control/DataSelectorOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataTransfertOW.py +7 -7
- orangecontrib/tomwer/widgets/control/DataValidatorOW.py +0 -1
- orangecontrib/tomwer/widgets/control/DataWatcherOW.py +0 -3
- orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +3 -2
- orangecontrib/tomwer/widgets/control/EmailOW.py +82 -0
- orangecontrib/tomwer/widgets/control/FilterOW.py +3 -3
- orangecontrib/tomwer/widgets/control/NXTomomillOW.py +1 -1
- orangecontrib/tomwer/widgets/control/NotifierOW.py +0 -1
- orangecontrib/tomwer/widgets/control/ReduceDarkFlatSelectorOW.py +93 -0
- orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +29 -5
- orangecontrib/tomwer/widgets/control/TimerOW.py +1 -2
- orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +0 -1
- orangecontrib/tomwer/widgets/control/VolumeSelector.py +0 -1
- orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +4 -10
- orangecontrib/tomwer/widgets/control/icons/email.png +0 -0
- orangecontrib/tomwer/widgets/control/icons/email.svg +58 -0
- orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.png +0 -0
- orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.svg +199 -0
- orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +0 -1
- orangecontrib/tomwer/widgets/debugtools/ObjectInspectorOW.py +0 -1
- orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +1 -2
- orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +1 -2
- orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +0 -1
- orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +0 -1
- orangecontrib/tomwer/widgets/other/PythonScriptOW.py +29 -1
- orangecontrib/tomwer/widgets/other/TomoObjsHub.py +28 -0
- orangecontrib/tomwer/widgets/other/icons/hub.png +0 -0
- orangecontrib/tomwer/widgets/other/icons/hub.svg +113 -0
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +18 -12
- orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +0 -2
- orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +21 -6
- orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +29 -7
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +18 -5
- orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +40 -13
- orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +37 -10
- orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +2 -3
- orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +5 -4
- orangecontrib/tomwer/widgets/stitching/StitcherOW.py +0 -1
- orangecontrib/tomwer/widgets/stitching/ZStitchingConfigOW.py +0 -1
- orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +10 -4
- orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +0 -1
- orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +0 -1
- orangecontrib/tomwer/widgets/visualization/RadioStackOW.py +7 -5
- orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -3
- orangecontrib/tomwer/widgets/visualization/SliceStackOW.py +7 -5
- orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +4 -4
- tomwer/__main__.py +139 -5
- tomwer/app/axis.py +16 -5
- tomwer/app/canvas_launcher/config.py +1 -1
- tomwer/app/canvas_launcher/mainwindow.py +164 -6
- tomwer/app/darkref.py +10 -181
- tomwer/app/darkrefpatch.py +10 -131
- tomwer/app/diffframe.py +11 -0
- tomwer/app/imagekeyeditor.py +12 -19
- tomwer/app/intensitynormalization.py +1 -0
- tomwer/app/lamino.py +7 -2
- tomwer/app/patchrawdarkflat.py +131 -0
- tomwer/app/radiostack.py +10 -0
- tomwer/app/reducedarkflat.py +205 -0
- tomwer/app/saaxis.py +27 -8
- tomwer/app/sadeltabeta.py +29 -8
- tomwer/app/samplemoved.py +11 -0
- tomwer/app/scanviewer.py +12 -0
- tomwer/app/sinogramviewer.py +11 -0
- tomwer/app/slicestack.py +11 -0
- tomwer/app/zstitching.py +12 -0
- tomwer/core/futureobject.py +4 -2
- tomwer/core/process/conditions/filters.py +26 -4
- tomwer/core/process/control/datadiscovery.py +4 -0
- tomwer/core/process/control/datawatcher/datawatcher.py +5 -1
- tomwer/core/process/control/email.py +148 -0
- tomwer/core/process/control/nxtomoconcatenate.py +9 -2
- tomwer/core/process/control/nxtomomill.py +58 -16
- tomwer/core/process/control/scanselector.py +4 -0
- tomwer/core/process/control/scantransfer.py +52 -23
- tomwer/core/process/control/test/test_concatenate_nxtomos.py +1 -0
- tomwer/core/process/control/test/test_email.py +52 -0
- tomwer/core/process/control/test/test_h52nx_process.py +106 -0
- tomwer/core/process/control/test/test_volume_link.py +5 -4
- tomwer/core/process/control/timer.py +27 -6
- tomwer/core/process/control/tomoobjserie.py +4 -0
- tomwer/core/process/control/volumeselector.py +4 -0
- tomwer/core/process/control/volumesymlink.py +47 -8
- tomwer/core/process/edit/darkflatpatch.py +49 -8
- tomwer/core/process/edit/imagekeyeditor.py +63 -13
- tomwer/core/process/reconstruction/axis/__init__.py +1 -1
- tomwer/core/process/reconstruction/axis/axis.py +61 -41
- tomwer/core/process/reconstruction/axis/params.py +4 -6
- tomwer/core/process/reconstruction/darkref/darkrefs.py +53 -16
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +12 -2
- tomwer/core/process/reconstruction/lamino/__init__.py +1 -1
- tomwer/core/process/reconstruction/lamino/tofu.py +22 -2
- tomwer/core/process/reconstruction/nabu/nabucommon.py +93 -14
- tomwer/core/process/reconstruction/nabu/nabuscores.py +70 -33
- tomwer/core/process/reconstruction/nabu/nabuslices.py +219 -41
- tomwer/core/process/reconstruction/nabu/nabuvolume.py +240 -108
- tomwer/core/process/reconstruction/nabu/utils.py +10 -36
- tomwer/core/process/reconstruction/normalization/normalization.py +10 -3
- tomwer/core/process/reconstruction/saaxis/__init__.py +1 -0
- tomwer/core/process/reconstruction/saaxis/saaxis.py +564 -376
- tomwer/core/process/reconstruction/sadeltabeta/__init__.py +1 -0
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +481 -268
- tomwer/core/process/reconstruction/scores/params.py +21 -8
- tomwer/core/process/reconstruction/test/test_darkref_copy.py +2 -0
- tomwer/core/process/reconstruction/test/test_saaxis.py +21 -8
- tomwer/core/process/reconstruction/test/test_sadeltabeta.py +8 -5
- tomwer/core/process/script/python.py +7 -2
- tomwer/core/process/stitching/nabustitcher.py +10 -3
- tomwer/core/process/task.py +2 -9
- tomwer/core/process/test/test_axis.py +25 -15
- tomwer/core/process/test/test_conditions.py +6 -6
- tomwer/core/process/test/test_dark_and_flat.py +20 -15
- tomwer/core/process/test/test_data_transfer.py +8 -8
- tomwer/core/process/test/test_data_watcher.py +1 -1
- tomwer/core/process/test/test_lamino.py +6 -6
- tomwer/core/process/test/test_nabu.py +13 -8
- tomwer/core/process/test/test_normalization.py +1 -0
- tomwer/core/process/test/test_timer.py +6 -6
- tomwer/core/process/visualization/dataviewer.py +4 -0
- tomwer/core/process/visualization/diffviewer.py +4 -0
- tomwer/core/process/visualization/imagestackviewer.py +4 -0
- tomwer/core/process/visualization/radiostack.py +4 -0
- tomwer/core/process/visualization/samplemoved.py +4 -0
- tomwer/core/process/visualization/sinogramviewer.py +4 -0
- tomwer/core/process/visualization/slicestack.py +4 -0
- tomwer/core/process/visualization/volumeviewer.py +4 -0
- tomwer/core/scan/hdf5scan.py +4 -4
- tomwer/core/scan/scanbase.py +5 -1
- tomwer/core/scan/test/test_process_registration.py +9 -9
- tomwer/core/settings.py +59 -1
- tomwer/core/test/test_lamino.py +2 -1
- tomwer/core/utils/__init__.py +16 -0
- tomwer/core/utils/locker.py +0 -1
- tomwer/core/utils/resource.py +6 -11
- tomwer/core/utils/scanutils.py +2 -0
- tomwer/gui/cluster/slurm.py +91 -7
- tomwer/gui/cluster/supervisor.py +16 -11
- tomwer/gui/cluster/test/test_cluster.py +16 -1
- tomwer/gui/conditions/filter.py +3 -3
- tomwer/gui/control/datalist.py +24 -11
- tomwer/gui/control/email.py +183 -0
- tomwer/gui/control/reducedarkflatselector.py +545 -0
- tomwer/gui/control/singletomoobj.py +23 -1
- tomwer/gui/control/test/test_email.py +35 -0
- tomwer/gui/control/test/test_reducedarkflat_selector.py +280 -0
- tomwer/gui/reconstruction/axis/CompareImages.py +1 -1
- tomwer/gui/reconstruction/axis/axis.py +10 -6
- tomwer/gui/reconstruction/axis/radioaxis.py +14 -6
- tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +2 -0
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +4 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +3 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +34 -33
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +1 -1
- tomwer/gui/reconstruction/normalization/intensity.py +5 -5
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +1 -0
- tomwer/gui/reconstruction/saaxis/saaxis.py +6 -6
- tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +6 -6
- tomwer/gui/reconstruction/scores/scoreplot.py +6 -4
- tomwer/gui/samplemoved/__init__.py +2 -2
- tomwer/gui/stackplot.py +18 -7
- tomwer/gui/stacks.py +2 -2
- tomwer/gui/stitching/stitchandbackground.py +2 -2
- tomwer/gui/stitching/stitching.py +1 -1
- tomwer/gui/stitching/stitching_raw.py +1 -1
- tomwer/gui/utils/__init__.py +1 -85
- tomwer/gui/utils/illustrations.py +1 -1
- tomwer/gui/utils/inputwidget.py +41 -36
- tomwer/gui/utils/slider.py +2 -2
- tomwer/gui/utils/utils.py +93 -0
- tomwer/gui/visualization/dataviewer.py +8 -5
- tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
- tomwer/gui/visualization/reconstructionparameters.py +26 -6
- tomwer/gui/visualization/sinogramviewer.py +7 -1
- tomwer/gui/visualization/test/test_reconstruction_parameters.py +2 -4
- tomwer/gui/visualization/volumeviewer.py +2 -0
- tomwer/resources/__init__.py +55 -43
- tomwer/resources/gui/icons/compose.png +0 -0
- tomwer/resources/gui/icons/compose.svg +75 -0
- tomwer/synctools/datatransfert.py +3 -1
- tomwer/synctools/stacks/edit/darkflatpatch.py +39 -34
- tomwer/synctools/stacks/edit/imagekeyeditor.py +8 -27
- tomwer/synctools/stacks/processingstack.py +45 -9
- tomwer/synctools/stacks/reconstruction/axis.py +6 -5
- tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -0
- tomwer/synctools/stacks/reconstruction/lamino.py +3 -3
- tomwer/synctools/stacks/reconstruction/nabu.py +49 -140
- tomwer/synctools/stacks/reconstruction/normalization.py +1 -0
- tomwer/synctools/stacks/reconstruction/saaxis.py +19 -33
- tomwer/synctools/stacks/reconstruction/sadeltabeta.py +16 -32
- tomwer/synctools/test/test_darkRefs.py +19 -10
- tomwer/synctools/test/test_foldertransfer.py +7 -7
- tomwer/third_party/nabu/preproc/phase.py +6 -8
- tomwer/third_party/nabu/utils.py +2 -3
- tomwer/version.py +1 -1
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/METADATA +15 -54
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/RECORD +219 -192
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/WHEEL +1 -1
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/entry_points.txt +3 -3
- /tomwer-1.2.0a1-py3.9-nspkg.pth → /tomwer-1.2.0a3-py3.11-nspkg.pth +0 -0
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/LICENSE +0 -0
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/namespace_packages.txt +0 -0
- {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/top_level.txt +0 -0
tomwer/gui/cluster/supervisor.py
CHANGED
@@ -88,11 +88,6 @@ class FutureTomwerScanObserverWidget(qt.QWidget):
|
|
88
88
|
|
89
89
|
# set up
|
90
90
|
self._convertWhenFinished.setChecked(True)
|
91
|
-
h_header = self.observationTable.horizontalHeader()
|
92
|
-
for column_index in (0, 2, 3, 4):
|
93
|
-
h_header.setSectionResizeMode(column_index, qt.QHeaderView.Interactive)
|
94
|
-
for column_index in (1,):
|
95
|
-
h_header.setSectionResizeMode(column_index, qt.QHeaderView.Stretch)
|
96
91
|
|
97
92
|
# connect signal / slot
|
98
93
|
self.filterWidget.sigChanged.connect(self._filterUpdated)
|
@@ -249,12 +244,12 @@ class _DatasetProcessModel(qt.QAbstractTableModel):
|
|
249
244
|
)
|
250
245
|
if trigger_update:
|
251
246
|
self._tomoObjStatus[future_tomo_obj] = status
|
247
|
+
obj_index = list(self._tomoObjStatus.keys()).index(future_tomo_obj)
|
252
248
|
try:
|
253
249
|
self.sigStatusUpdated.emit(future_tomo_obj, status)
|
254
250
|
except Exception:
|
255
251
|
pass
|
256
252
|
else:
|
257
|
-
obj_index = list(self._tomoObjStatus.keys()).index(future_tomo_obj)
|
258
253
|
self.dataChanged.emit(
|
259
254
|
self.createIndex(obj_index, 0),
|
260
255
|
self.createIndex(obj_index, len(self._headers) - 1),
|
@@ -353,11 +348,21 @@ class _DatasetProcessModel(qt.QAbstractTableModel):
|
|
353
348
|
|
354
349
|
|
355
350
|
class ObservationTable(qt.QTableView):
|
356
|
-
def
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
351
|
+
def sizeHintForColumn(self, column):
|
352
|
+
# warning: to be called we need to call resizeColumnsToContents upper
|
353
|
+
if column == 1: # dataset column
|
354
|
+
return 400
|
355
|
+
elif column in (
|
356
|
+
0,
|
357
|
+
2,
|
358
|
+
3,
|
359
|
+
4,
|
360
|
+
): # start-time, status, requester, slurm-job
|
361
|
+
return 55
|
362
|
+
elif column == 5:
|
363
|
+
return 200
|
364
|
+
else:
|
365
|
+
return super().sizeHintForColumn(column)
|
361
366
|
|
362
367
|
|
363
368
|
class FilterWidget(qt.QGroupBox):
|
@@ -32,8 +32,13 @@ from silx.gui import qt
|
|
32
32
|
from silx.gui.utils.testutils import TestCaseQt
|
33
33
|
|
34
34
|
from tomwer.core.settings import SlurmSettings
|
35
|
-
from tomwer.gui.cluster.slurm import
|
35
|
+
from tomwer.gui.cluster.slurm import (
|
36
|
+
SlurmSettingsMode,
|
37
|
+
SlurmSettingsWidget,
|
38
|
+
SlurmSettingsWindow,
|
39
|
+
)
|
36
40
|
from tomwer.tests.utils import skip_gui_test
|
41
|
+
from tomwer.tests.conftest import qtapp # noqa F401
|
37
42
|
|
38
43
|
|
39
44
|
@pytest.mark.skipif(skip_gui_test(), reason="skip gui test")
|
@@ -78,3 +83,13 @@ class TestSlurmWidget(TestCaseQt):
|
|
78
83
|
assert self.slurmWidget.getMemory() == 156
|
79
84
|
assert self.slurmWidget.getQueue() == "test-queue"
|
80
85
|
assert self.slurmWidget.getNGPU() == 5
|
86
|
+
|
87
|
+
|
88
|
+
def test_SlurmSettingsWindow(qtapp): # noqa F811
|
89
|
+
"""
|
90
|
+
test that slurm SettingsWindow can load all the different slurm settings modes
|
91
|
+
"""
|
92
|
+
widget = SlurmSettingsWindow()
|
93
|
+
for mode in SlurmSettingsMode:
|
94
|
+
widget.setCurrentSettingsMode(mode)
|
95
|
+
widget.getConfiguration()
|
tomwer/gui/conditions/filter.py
CHANGED
@@ -34,7 +34,7 @@ __date__ = "19/07/2018"
|
|
34
34
|
|
35
35
|
from silx.gui import qt
|
36
36
|
|
37
|
-
from tomwer.core.process.conditions.filters import
|
37
|
+
from tomwer.core.process.conditions.filters import FileNameFilterTask
|
38
38
|
from tomwer.gui import icons
|
39
39
|
from tomwer.gui.utils.sandboxes import (
|
40
40
|
RegularExpressionSandBox,
|
@@ -66,7 +66,7 @@ class FileNameFilterWidget(qt.QWidget):
|
|
66
66
|
|
67
67
|
self.layout().addWidget(qt.QLabel("filter type:", self), 1, 0)
|
68
68
|
self._filterTypeCB = qt.QComboBox(parent=self)
|
69
|
-
for filter_type in
|
69
|
+
for filter_type in FileNameFilterTask.FILTER_TYPES:
|
70
70
|
self._filterTypeCB.addItem(filter_type)
|
71
71
|
self.layout().addWidget(self._filterTypeCB, 1, 1, 1, 2)
|
72
72
|
|
@@ -84,7 +84,7 @@ class FileNameFilterWidget(qt.QWidget):
|
|
84
84
|
|
85
85
|
# set up
|
86
86
|
self._sandBoxPB.setVisible(False)
|
87
|
-
self._filterTypeCB.setCurrentText(
|
87
|
+
self._filterTypeCB.setCurrentText(FileNameFilterTask._DEFAULT_FILTER_TYPE)
|
88
88
|
|
89
89
|
self.sandboxDialog = None
|
90
90
|
|
tomwer/gui/control/datalist.py
CHANGED
@@ -509,7 +509,9 @@ class GenericScanListDialog(_DataListDialog):
|
|
509
509
|
files_or_folders = dialog.files_selected()
|
510
510
|
added_scans = []
|
511
511
|
for file_or_folder in files_or_folders:
|
512
|
-
|
512
|
+
new_scans = self.add(file_or_folder)
|
513
|
+
if new_scans is not None:
|
514
|
+
added_scans.extend(new_scans)
|
513
515
|
super()._callbackAddPath()
|
514
516
|
self.datalist.setMySelection(added_scans)
|
515
517
|
|
@@ -530,7 +532,9 @@ class VolumeListDialog(_DataListDialog):
|
|
530
532
|
files_or_folders = dialog.files_selected()
|
531
533
|
added_volumes = []
|
532
534
|
for file_or_folder in files_or_folders:
|
533
|
-
|
535
|
+
new_volumes = self.add(file_or_folder)
|
536
|
+
if new_volumes is not None:
|
537
|
+
added_volumes.extend(new_volumes)
|
534
538
|
super()._callbackAddPath()
|
535
539
|
self.datalist.setMySelection(added_volumes)
|
536
540
|
|
@@ -765,18 +769,27 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
765
769
|
|
766
770
|
def _copyRequested(self):
|
767
771
|
clipboard = qt.QGuiApplication.clipboard()
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
+
|
773
|
+
def get_info(item):
|
774
|
+
user_data = item.data(qt.Qt.UserRole)
|
775
|
+
if isinstance(user_data, TomwerObject):
|
776
|
+
return user_data.get_identifier().to_str()
|
777
|
+
else:
|
778
|
+
return str(user_data)
|
779
|
+
|
780
|
+
selection = [get_info(item) for item in self.selectedItems()]
|
781
|
+
clipboard.setText("\n".join(selection))
|
772
782
|
|
773
783
|
def _pasteRequested(self):
|
774
784
|
clipboard = qt.QGuiApplication.clipboard()
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
785
|
+
identifiers = clipboard.text()
|
786
|
+
# handle paste of several lines...
|
787
|
+
identifiers.replace(";", "\n")
|
788
|
+
for identifier in identifiers.split("\n"):
|
789
|
+
try:
|
790
|
+
self.add(identifier)
|
791
|
+
except Exception as e:
|
792
|
+
logger.error(f"Failed to add {identifier}. Error is {e}")
|
780
793
|
|
781
794
|
|
782
795
|
class GenericScanList(_TomwerObjectList):
|
@@ -0,0 +1,183 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
from silx.gui import qt
|
3
|
+
from tomwer.gui import icons as tomwericons
|
4
|
+
from tomwer.core.utils import concatenate_dict
|
5
|
+
|
6
|
+
|
7
|
+
class EmailComposition(qt.QWidget):
|
8
|
+
"""
|
9
|
+
Widget used to compose an email
|
10
|
+
|
11
|
+
Please see https://confluence.esrf.fr/display/SCKB/Rules+about+email for email rules at esrf
|
12
|
+
"""
|
13
|
+
|
14
|
+
sigChanged = qt.Signal()
|
15
|
+
"""emit when the composition changed"""
|
16
|
+
|
17
|
+
def __init__(self, parent: Optional[qt.QWidget]) -> None:
|
18
|
+
super().__init__(parent)
|
19
|
+
self.setLayout(qt.QFormLayout())
|
20
|
+
# from
|
21
|
+
self._fromAddressesQLE = qt.QLineEdit(self)
|
22
|
+
singleEmailValidator = qt.QRegularExpressionValidator(
|
23
|
+
qt.QRegularExpression(
|
24
|
+
r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"
|
25
|
+
),
|
26
|
+
self._fromAddressesQLE,
|
27
|
+
)
|
28
|
+
self._fromAddressesQLE.setValidator(singleEmailValidator)
|
29
|
+
self.layout().addRow("from", self._fromAddressesQLE)
|
30
|
+
# to
|
31
|
+
self._toAdressesQLE = qt.QLineEdit(self)
|
32
|
+
severalEmailValidator = qt.QRegularExpressionValidator(
|
33
|
+
qt.QRegularExpression(
|
34
|
+
r"(([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)(\s*;\s*|\s*$))*"
|
35
|
+
),
|
36
|
+
self,
|
37
|
+
)
|
38
|
+
self._toAdressesQLE.setValidator(severalEmailValidator)
|
39
|
+
self.layout().addRow("to", self._toAdressesQLE)
|
40
|
+
# subject
|
41
|
+
self._subjectQLE = qt.QLineEdit("tomwer: {tomo_obj_short_id} received", self)
|
42
|
+
tooltip = """
|
43
|
+
this section can contain some predefine `keywords` and will be formatting before sending the email.\n
|
44
|
+
Reserve keywords are: \n
|
45
|
+
- {tomo_obj_short_id}: tomo_obj short identifier
|
46
|
+
- {tomo_obj_id}: tomo_obj id
|
47
|
+
- {ls_tomo_obj}: ls of the scan folder
|
48
|
+
- {timestamp}: current time
|
49
|
+
- {footnote}: some footnote defined by tomwer
|
50
|
+
- {dataset_processing_states}: list dataset state regarding met processes
|
51
|
+
"""
|
52
|
+
self._subjectQLE.setToolTip(tooltip)
|
53
|
+
self.layout().addRow("subject", self._subjectQLE)
|
54
|
+
# text
|
55
|
+
self._textQLE = qt.QPlainTextEdit(
|
56
|
+
"{tomo_obj_id} received at {timestamp} \n\nprocesses:\n{dataset_processing_states}\n\nfile listening:\n{ls_tomo_obj}\n\nInfo: {footnote}"
|
57
|
+
)
|
58
|
+
self._textQLE.setToolTip(tooltip)
|
59
|
+
self.layout().addRow(self._textQLE)
|
60
|
+
|
61
|
+
# connect signal / slot
|
62
|
+
self._fromAddressesQLE.editingFinished.connect(self._changed)
|
63
|
+
self._toAdressesQLE.editingFinished.connect(self._changed)
|
64
|
+
self._subjectQLE.editingFinished.connect(self._changed)
|
65
|
+
self._textQLE.textChanged.connect(self._changed)
|
66
|
+
|
67
|
+
def _changed(self):
|
68
|
+
self.sigChanged.emit()
|
69
|
+
|
70
|
+
def getToAddrs(self) -> tuple:
|
71
|
+
adresses = self._toAdressesQLE.text().replace(" ", "")
|
72
|
+
adresses.replace(",", ";")
|
73
|
+
return tuple(set(adresses.split(";")))
|
74
|
+
|
75
|
+
def getConfiguration(self) -> dict:
|
76
|
+
return {
|
77
|
+
"subject": self._subjectQLE.text(),
|
78
|
+
"from_addr": self._fromAddressesQLE.text(),
|
79
|
+
"to_addrs": self.getToAddrs(),
|
80
|
+
"text": self._textQLE.toPlainText(),
|
81
|
+
}
|
82
|
+
|
83
|
+
def setConfiguration(self, config: dict):
|
84
|
+
assert isinstance(config, dict)
|
85
|
+
subject = config.get("subject", None)
|
86
|
+
if subject is not None:
|
87
|
+
self._subjectQLE.setText(str(subject))
|
88
|
+
from_addr = config.get("from_addr", None)
|
89
|
+
if from_addr is not None:
|
90
|
+
self._fromAddressesQLE.setText(str(from_addr))
|
91
|
+
to_addrs = config.get("to_addrs", None)
|
92
|
+
if to_addrs is not None:
|
93
|
+
if not isinstance(to_addrs, str):
|
94
|
+
to_addrs = ";".join(to_addrs)
|
95
|
+
self._toAdressesQLE.setText(str(to_addrs))
|
96
|
+
text = config.get("text", None)
|
97
|
+
if text is not None:
|
98
|
+
self._textQLE.setPlainText(str(text))
|
99
|
+
|
100
|
+
|
101
|
+
class EmailSettings(qt.QWidget):
|
102
|
+
"""
|
103
|
+
Widget to set up mail server
|
104
|
+
"""
|
105
|
+
|
106
|
+
sigChanged = qt.Signal()
|
107
|
+
"""emit when the settings changed"""
|
108
|
+
|
109
|
+
def __init__(self, parent: Optional[qt.QWidget]) -> None:
|
110
|
+
super().__init__(parent)
|
111
|
+
self.setLayout(qt.QFormLayout(self))
|
112
|
+
# server
|
113
|
+
self._hostQLE = qt.QLineEdit("smtps.esrf.fr", self)
|
114
|
+
self.layout().addRow("host", self._hostQLE)
|
115
|
+
# port
|
116
|
+
self._portQLE = qt.QLineEdit("0", self)
|
117
|
+
self._portQLE.setValidator(qt.QIntValidator(self._portQLE))
|
118
|
+
self.layout().addRow("port", self._portQLE)
|
119
|
+
|
120
|
+
# connect signal / slot
|
121
|
+
self._hostQLE.editingFinished.connect(self._changed)
|
122
|
+
self._portQLE.editingFinished.connect(self._changed)
|
123
|
+
|
124
|
+
def _changed(self):
|
125
|
+
self.sigChanged.emit()
|
126
|
+
|
127
|
+
def getConfiguration(self) -> dict:
|
128
|
+
return {"host": self._hostQLE.text(), "port": int(self._portQLE.text())}
|
129
|
+
|
130
|
+
def setConfiguration(self, config: dict):
|
131
|
+
server = config.get("host", None)
|
132
|
+
if server is not None:
|
133
|
+
self._hostQLE.setText(str(server))
|
134
|
+
port = config.get("port", None)
|
135
|
+
if port is not None:
|
136
|
+
self._portQLE.setText(str(port))
|
137
|
+
|
138
|
+
|
139
|
+
class Emailwidget(qt.QTabWidget):
|
140
|
+
"""
|
141
|
+
Main widget to send email
|
142
|
+
"""
|
143
|
+
|
144
|
+
sigChanged = qt.Signal()
|
145
|
+
"""emit when the email settings or composition changed"""
|
146
|
+
|
147
|
+
def __init__(self, parent: Optional[qt.QWidget] = None) -> None:
|
148
|
+
super().__init__(parent)
|
149
|
+
|
150
|
+
self.setTabPosition(qt.QTabWidget.East)
|
151
|
+
|
152
|
+
self._compositionWidget = EmailComposition(self)
|
153
|
+
composeIcon = tomwericons.getQIcon("compose")
|
154
|
+
self.addTab(
|
155
|
+
self._compositionWidget,
|
156
|
+
composeIcon,
|
157
|
+
"",
|
158
|
+
)
|
159
|
+
|
160
|
+
self._serverSettingsWidget = EmailSettings(self)
|
161
|
+
settingsIcon = tomwericons.getQIcon("parameters")
|
162
|
+
self.addTab(
|
163
|
+
self._serverSettingsWidget,
|
164
|
+
settingsIcon,
|
165
|
+
"",
|
166
|
+
)
|
167
|
+
|
168
|
+
# connect signal / slot
|
169
|
+
self._compositionWidget.sigChanged.connect(self._changed)
|
170
|
+
self._serverSettingsWidget.sigChanged.connect(self._changed)
|
171
|
+
|
172
|
+
def _changed(self):
|
173
|
+
self.sigChanged.emit()
|
174
|
+
|
175
|
+
def getConfiguration(self) -> dict:
|
176
|
+
return concatenate_dict(
|
177
|
+
self._serverSettingsWidget.getConfiguration(),
|
178
|
+
self._compositionWidget.getConfiguration(),
|
179
|
+
)
|
180
|
+
|
181
|
+
def setConfiguration(self, config: dict):
|
182
|
+
self._serverSettingsWidget.setConfiguration(config)
|
183
|
+
self._compositionWidget.setConfiguration(config)
|