tomwer 1.0.3__py3-none-any.whl → 1.1.0__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.
Files changed (269) hide show
  1. orangecontrib/tomwer/tutorials/EBS_tomo_listener.ows +39 -0
  2. orangecontrib/tomwer/tutorials/cast_volume.ows +34 -0
  3. orangecontrib/tomwer/tutorials/simple_slice_reconstruction.ows +39 -0
  4. orangecontrib/tomwer/tutorials/simple_volume_local_reconstruction.ows +49 -0
  5. orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +59 -0
  6. orangecontrib/tomwer/tutorials/using_saaxis_to_find_cor.ows +44 -0
  7. orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +1 -1
  8. orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +14 -4
  9. orangecontrib/tomwer/widgets/cluster/__init__.py +1 -1
  10. orangecontrib/tomwer/widgets/control/DataListOW.py +12 -5
  11. orangecontrib/tomwer/widgets/control/DataListenerOW.py +18 -9
  12. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +13 -6
  13. orangecontrib/tomwer/widgets/control/DataTransfertOW.py +3 -5
  14. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +8 -4
  15. orangecontrib/tomwer/widgets/control/DataWatcherOW.py +4 -6
  16. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +49 -62
  17. orangecontrib/tomwer/widgets/control/FilterOW.py +2 -4
  18. orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +93 -0
  19. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +135 -129
  20. orangecontrib/tomwer/widgets/control/NotifierOW.py +34 -9
  21. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +3 -5
  22. orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +19 -13
  23. orangecontrib/tomwer/widgets/control/VolumeSelector.py +12 -4
  24. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +11 -7
  25. orangecontrib/tomwer/widgets/control/icons/notification.svg +4 -4
  26. orangecontrib/tomwer/widgets/control/icons/nxtomomill.png +0 -0
  27. orangecontrib/tomwer/widgets/control/icons/nxtomomill.svg +8 -5
  28. orangecontrib/tomwer/widgets/control/icons/tomoobjserie.png +0 -0
  29. orangecontrib/tomwer/widgets/control/icons/tomoobjserie.svg +73 -78
  30. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +16 -4
  31. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +100 -0
  32. orangecontrib/tomwer/widgets/edit/icons/image_key_editor.png +0 -0
  33. orangecontrib/tomwer/widgets/edit/icons/image_key_upgrader.png +0 -0
  34. orangecontrib/tomwer/widgets/edit/icons/nx_tomo_editor.png +0 -0
  35. orangecontrib/tomwer/widgets/edit/icons/nx_tomo_editor.svg +123 -0
  36. orangecontrib/tomwer/widgets/edit/test/test_dark_flat_patch.py +21 -1
  37. orangecontrib/tomwer/widgets/edit/test/test_image_key_editor.py +1 -1
  38. orangecontrib/tomwer/widgets/edit/test/test_image_key_upgrader.py +1 -1
  39. orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +25 -0
  40. orangecontrib/tomwer/widgets/other/PythonScriptOW.py +19 -11
  41. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +20 -14
  42. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +24 -10
  43. orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +26 -21
  44. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +29 -12
  45. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +44 -17
  46. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +28 -20
  47. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +24 -18
  48. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +6 -6
  49. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +4 -2
  50. orangecontrib/tomwer/widgets/reconstruction/icons/nabu_2d.png +0 -0
  51. orangecontrib/tomwer/widgets/reconstruction/icons/nabu_2d.svg +11 -8
  52. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +10 -4
  53. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  54. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +69 -0
  55. orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +2 -4
  56. orangecontrib/tomwer/widgets/visualization/icons/nx_tomo_metadata_viewer.png +0 -0
  57. orangecontrib/tomwer/widgets/visualization/icons/nx_tomo_metadata_viewer.svg +105 -0
  58. tomwer/__main__.py +10 -5
  59. tomwer/app/canvas_launcher/config.py +10 -10
  60. tomwer/app/canvas_launcher/mainwindow.py +68 -6
  61. tomwer/app/canvas_launcher/widgetsscheme.py +1 -3
  62. tomwer/app/darkref.py +16 -12
  63. tomwer/app/imagekeyeditor.py +2 -2
  64. tomwer/app/imagekeyupgrader.py +104 -0
  65. tomwer/app/intensitynormalization.py +0 -1
  66. tomwer/app/nxtomoeditor.py +103 -0
  67. tomwer/app/rsync.py +1 -1
  68. tomwer/core/cluster/cluster.py +1 -1
  69. tomwer/core/futureobject.py +1 -0
  70. tomwer/core/process/control/datalistener/datalistener.py +7 -1
  71. tomwer/core/process/control/datalistener/rpcserver.py +3 -4
  72. tomwer/core/process/control/datawatcher/datawatcher.py +18 -18
  73. tomwer/core/process/control/datawatcher/datawatcherobserver.py +5 -8
  74. tomwer/core/process/control/datawatcher/datawatcherprocess.py +2 -3
  75. tomwer/core/process/control/datawatcher/edfdwprocess.py +2 -2
  76. tomwer/core/process/control/nxtomomill.py +33 -58
  77. tomwer/core/process/control/scanlist.py +2 -1
  78. tomwer/core/process/control/scanselector.py +7 -0
  79. tomwer/core/process/control/scantransfer.py +2 -2
  80. tomwer/core/process/control/scanvalidator.py +6 -5
  81. tomwer/core/process/control/singletomoobj.py +2 -1
  82. tomwer/core/process/control/timer.py +2 -1
  83. tomwer/core/process/control/tomoobjserie.py +8 -2
  84. tomwer/core/process/control/volumeselector.py +2 -1
  85. tomwer/core/process/control/volumesymlink.py +2 -1
  86. tomwer/core/process/edit/darkflatpatch.py +2 -1
  87. tomwer/core/process/edit/imagekeyeditor.py +4 -3
  88. tomwer/core/process/reconstruction/axis/axis.py +29 -32
  89. tomwer/core/process/reconstruction/axis/mode.py +3 -2
  90. tomwer/core/process/reconstruction/axis/params.py +35 -16
  91. tomwer/core/process/reconstruction/darkref/darkrefs.py +90 -707
  92. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +44 -16
  93. tomwer/core/process/reconstruction/darkref/params.py +62 -67
  94. tomwer/core/process/reconstruction/lamino/tofu.py +1 -2
  95. tomwer/core/process/reconstruction/nabu/castvolume.py +21 -26
  96. tomwer/core/process/reconstruction/nabu/nabucommon.py +36 -38
  97. tomwer/core/process/reconstruction/nabu/nabuscores.py +28 -13
  98. tomwer/core/process/reconstruction/nabu/nabuslices.py +41 -14
  99. tomwer/core/process/reconstruction/nabu/nabuvolume.py +21 -12
  100. tomwer/core/process/reconstruction/nabu/utils.py +32 -3
  101. tomwer/core/process/reconstruction/normalization/normalization.py +9 -8
  102. tomwer/core/process/reconstruction/saaxis/saaxis.py +46 -20
  103. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +38 -12
  104. tomwer/core/process/reconstruction/test/__init__.py +0 -39
  105. tomwer/core/process/reconstruction/test/test_axis_params.py +25 -3
  106. tomwer/core/process/reconstruction/test/test_darkref_copy.py +117 -1
  107. tomwer/core/process/script/python.py +16 -12
  108. tomwer/core/process/task.py +3 -7
  109. tomwer/core/process/test/test_axis.py +1 -1
  110. tomwer/core/process/test/test_dark_and_flat.py +41 -111
  111. tomwer/core/process/test/test_data_listener.py +0 -29
  112. tomwer/core/process/test/test_data_transfer.py +10 -14
  113. tomwer/core/process/test/test_nabu.py +1 -1
  114. tomwer/core/process/test/test_normalization.py +1 -1
  115. tomwer/core/process/visualization/liveslice.py +6 -0
  116. tomwer/core/scan/blissscan.py +37 -2
  117. tomwer/core/scan/edfscan.py +19 -8
  118. tomwer/core/scan/hdf5scan.py +10 -4
  119. tomwer/core/scan/scanbase.py +35 -29
  120. tomwer/core/scan/scanfactory.py +3 -17
  121. tomwer/core/scan/test/test_h5.py +1 -1
  122. tomwer/core/scan/test/test_process_registration.py +0 -11
  123. tomwer/core/scan/test/test_scan.py +32 -30
  124. tomwer/core/settings.py +2 -2
  125. tomwer/core/test/test_utils.py +1 -1
  126. tomwer/core/tomwer_object.py +19 -0
  127. tomwer/core/utils/__init__.py +0 -45
  128. tomwer/core/utils/char.py +2 -0
  129. tomwer/core/utils/gpu.py +5 -5
  130. tomwer/core/utils/nxtomoutils.py +2 -2
  131. tomwer/core/utils/scanutils.py +50 -0
  132. tomwer/core/utils/volumeutils.py +13 -0
  133. tomwer/core/volume/edfvolume.py +4 -0
  134. tomwer/core/volume/hdf5volume.py +4 -0
  135. tomwer/core/volume/jp2kvolume.py +4 -0
  136. tomwer/core/volume/rawvolume.py +22 -5
  137. tomwer/core/volume/tiffvolume.py +4 -0
  138. tomwer/core/volume/volumebase.py +19 -12
  139. tomwer/core/volume/volumefactory.py +20 -1
  140. tomwer/gui/cluster/slurm.py +1 -1
  141. tomwer/gui/cluster/supervisor.py +0 -2
  142. tomwer/gui/cluster/test/test_cluster.py +2 -2
  143. tomwer/gui/control/datalist.py +109 -36
  144. tomwer/gui/control/datatransfert.py +1 -1
  145. tomwer/gui/control/datawatcher/configuration.py +0 -2
  146. tomwer/gui/control/datawatcher/datawatcher.py +23 -13
  147. tomwer/gui/control/datawatcher/datawatcherobserver.py +1 -1
  148. tomwer/gui/control/observations.py +0 -3
  149. tomwer/gui/control/selectorwidgetbase.py +42 -12
  150. tomwer/gui/control/serie/seriecreator.py +967 -0
  151. tomwer/{web/__init__.py → gui/control/serie/seriewaiter.py} +5 -7
  152. tomwer/gui/control/singletomoobj.py +15 -4
  153. tomwer/gui/control/test/test_datalist.py +1 -1
  154. tomwer/gui/control/test/test_datalistener.py +1 -1
  155. tomwer/gui/control/test/test_inputwidget.py +1 -1
  156. tomwer/gui/control/test/test_process_manager.py +1 -13
  157. tomwer/gui/control/test/test_scanselector.py +1 -1
  158. tomwer/gui/control/test/test_scanvalidator.py +1 -1
  159. tomwer/gui/control/test/test_single_tomo_obj.py +1 -1
  160. tomwer/gui/control/test/test_volume_dialog.py +19 -7
  161. tomwer/gui/control/test/test_volumeselector.py +4 -4
  162. tomwer/gui/debugtools/datasetgenerator.py +1 -9
  163. tomwer/gui/edit/dkrfpatch.py +2 -3
  164. tomwer/gui/edit/imagekeyeditor.py +12 -11
  165. tomwer/gui/edit/nxtomoeditor.py +475 -0
  166. tomwer/gui/edit/test/test_dkrf_patch.py +2 -14
  167. tomwer/gui/edit/test/test_image_key_editor.py +2 -2
  168. tomwer/gui/edit/test/test_nx_editor.py +155 -0
  169. tomwer/gui/icons.py +0 -1
  170. tomwer/gui/qfolderdialog.py +11 -0
  171. tomwer/gui/reconstruction/axis/CompareImages.py +27 -29
  172. tomwer/gui/reconstruction/axis/axis.py +2 -0
  173. tomwer/gui/reconstruction/axis/radioaxis.py +70 -14
  174. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +7 -9
  175. tomwer/gui/reconstruction/darkref/darkrefwidget.py +22 -24
  176. tomwer/gui/reconstruction/lamino/tofu/projections.py +1 -1
  177. tomwer/gui/reconstruction/lamino/tofu/tofu.py +3 -3
  178. tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +4 -4
  179. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +10 -5
  180. tomwer/gui/reconstruction/nabu/castvolume.py +103 -24
  181. tomwer/gui/reconstruction/nabu/check.py +1 -1
  182. tomwer/gui/reconstruction/nabu/nabuconfig/ctf.py +352 -0
  183. tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +0 -9
  184. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +1 -1
  185. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +18 -19
  186. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +30 -7
  187. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +26 -15
  188. tomwer/gui/reconstruction/nabu/slices.py +10 -4
  189. tomwer/gui/reconstruction/nabu/slurm.py +1 -1
  190. tomwer/gui/reconstruction/nabu/volume.py +13 -7
  191. tomwer/gui/reconstruction/normalization/intensity.py +1 -5
  192. tomwer/gui/reconstruction/saaxis/corrangeselector.py +10 -37
  193. tomwer/gui/reconstruction/saaxis/saaxis.py +11 -7
  194. tomwer/gui/reconstruction/saaxis/sliceselector.py +11 -26
  195. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +13 -8
  196. tomwer/gui/reconstruction/scores/scoreplot.py +67 -62
  197. tomwer/gui/reconstruction/test/test_axis.py +2 -2
  198. tomwer/gui/reconstruction/test/test_lamino.py +2 -2
  199. tomwer/gui/reconstruction/test/test_nabu.py +14 -1
  200. tomwer/gui/reconstruction/test/test_saaxis.py +8 -17
  201. tomwer/gui/reconstruction/test/test_sadeltabeta.py +7 -13
  202. tomwer/gui/stackplot.py +11 -28
  203. tomwer/gui/test/test_axis_gui.py +4 -4
  204. tomwer/gui/test/test_qfolder_dialog.py +12 -0
  205. tomwer/gui/utils/inputwidget.py +42 -22
  206. tomwer/gui/utils/lineselector/lineselector.py +13 -21
  207. tomwer/gui/utils/scandescription.py +2 -4
  208. tomwer/gui/utils/slider.py +1 -102
  209. tomwer/gui/utils/unitsystem.py +48 -11
  210. tomwer/gui/visualization/dataviewer.py +24 -17
  211. tomwer/gui/visualization/diffviewer/diffviewer.py +2 -11
  212. tomwer/gui/visualization/nxtomometadata.py +21 -0
  213. tomwer/gui/visualization/scanoverview.py +0 -1
  214. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +72 -0
  215. tomwer/gui/visualization/test/test_stacks.py +1 -1
  216. tomwer/gui/visualization/tomoobjoverview.py +49 -0
  217. tomwer/gui/visualization/volumeoverview.py +64 -0
  218. tomwer/gui/visualization/volumeviewer.py +1 -1
  219. tomwer/io/utils/utils.py +2 -2
  220. tomwer/resources/gui/icons/multi-document-save.png +0 -0
  221. tomwer/resources/gui/icons/multi-document-save.svg +101 -0
  222. tomwer/resources/gui/illustrations/ctf_z1.png +0 -0
  223. tomwer/resources/gui/illustrations/ctf_z1.svg +471 -0
  224. tomwer/synctools/axis.py +0 -1
  225. tomwer/synctools/darkref.py +0 -1
  226. tomwer/synctools/datalistener.py +5 -1
  227. tomwer/synctools/imageloaderthread.py +2 -2
  228. tomwer/synctools/saaxis.py +0 -1
  229. tomwer/synctools/sadeltabeta.py +0 -1
  230. tomwer/synctools/stacks/edit/imagekeyeditor.py +1 -1
  231. tomwer/synctools/stacks/processingstack.py +2 -2
  232. tomwer/synctools/stacks/reconstruction/castvolume.py +1 -0
  233. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -1
  234. tomwer/synctools/stacks/reconstruction/lamino.py +1 -3
  235. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +0 -2
  236. tomwer/synctools/test/test_darkRefs.py +32 -149
  237. tomwer/synctools/test/test_foldertransfer.py +1 -1
  238. tomwer/synctools/test/test_scanstages.py +2 -2
  239. tomwer/tests/conftest.py +51 -0
  240. tomwer/{test → tests}/test_scripts.py +1 -1
  241. tomwer/tests/test_utils.py +10 -0
  242. tomwer/{test → tests}/utils/utilstest.py +0 -11
  243. tomwer/version.py +3 -3
  244. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/METADATA +14 -16
  245. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/RECORD +255 -235
  246. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/WHEEL +1 -1
  247. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/entry_points.txt +6 -0
  248. orangecontrib/tomwer/setup.py +0 -45
  249. orangecontrib/tomwer/widgets/setup.py +0 -49
  250. tomwer/app/process.py +0 -153
  251. tomwer/core/process/reconstruction/nabu/slurm.py +0 -36
  252. tomwer/core/process/reconstruction/utils/nabu_slice_exec.py +0 -10
  253. tomwer/core/utils/laminoutils.py +0 -80
  254. tomwer/gui/utils/lineselector/lineselection.py +0 -76
  255. tomwer/setup.py +0 -52
  256. tomwer/slurm/executor.py +0 -36
  257. tomwer/slurm/job.py +0 -349
  258. tomwer/slurm/utils.py +0 -44
  259. tomwer/web/client.py +0 -43
  260. tomwer/web/config.py +0 -36
  261. tomwer/web/test/test_graylog_connection.py +0 -59
  262. {tomwer/slurm → orangecontrib/tomwer/tutorials}/__init__.py +0 -0
  263. /tomwer/{test → gui/control/serie}/__init__.py +0 -0
  264. /tomwer/{web/test → tests}/__init__.py +0 -0
  265. /tomwer/{test → tests}/utils/__init__.py +0 -0
  266. /tomwer-1.0.3-py3.8-nspkg.pth → /tomwer-1.1.0-py3.9-nspkg.pth +0 -0
  267. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/LICENSE +0 -0
  268. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/namespace_packages.txt +0 -0
  269. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/top_level.txt +0 -0
@@ -29,10 +29,12 @@ __authors__ = ["H. Payno"]
29
29
  __license__ = "MIT"
30
30
  __date__ = "11/08/2022"
31
31
 
32
+ import logging
32
33
  import h5py
33
34
  import numpy
34
35
  import time
35
36
  import os
37
+ from typing import Any
36
38
  from tomoscan.io import HDF5File
37
39
  from tomoscan.esrf.scan.mock import MockEDF as _MockEDF, MockHDF5 as _MockHDF5
38
40
  from tomoscan.test.utils import MockContext
@@ -41,6 +43,8 @@ from tomwer.core.scan.hdf5scan import HDF5TomoScan
41
43
  from tomwer.core.scan.scanfactory import ScanFactory
42
44
  from silx.io.utils import h5py_read_dataset
43
45
 
46
+ _logger = logging.getLogger(__name__)
47
+
44
48
 
45
49
  class MockHDF5(_MockHDF5):
46
50
  def __init__(self, *args, **kwargs):
@@ -391,3 +395,49 @@ class HDF5MockContext(MockContext, mock_class=MockHDF5):
391
395
  return MockHDF5(
392
396
  scan_path=self._scan_path, n_proj=self._n_proj, **self._mocks_params
393
397
  ).scan
398
+
399
+
400
+ def data_identifier_to_scan(data_identifier: Any):
401
+ """
402
+ from a identifier (as str) try to create a scan.
403
+ Mostly used when 'data' parameter is set from ewoks. In this case we expect it to be a (string) identifier
404
+ """
405
+ if isinstance(data_identifier, str):
406
+ return ScanFactory.create_tomo_object_from_identifier(data_identifier)
407
+ else:
408
+ return data_identifier
409
+
410
+
411
+ def format_output_location(location: str, scan):
412
+ """
413
+ format possible keys from the location like {scan_dir} or {scan_path}
414
+
415
+ :param location:
416
+ :param scan:
417
+ :return:
418
+ """
419
+ if scan is None:
420
+ _logger.warning("scan is !none, enable to format the nabu output location")
421
+
422
+ keywords = {
423
+ "scan_dir_name": scan.scan_dir_name(),
424
+ "scan_basename": scan.scan_basename(),
425
+ "scan_parent_dir_basename": scan.scan_parent_dir_basename(),
426
+ }
427
+
428
+ # filter necessary keywords
429
+ def get_necessary_keywords():
430
+ import string
431
+
432
+ formatter = string.Formatter()
433
+ return [field for _, field, _, _ in formatter.parse(location) if field]
434
+
435
+ requested_keywords = get_necessary_keywords()
436
+
437
+ def keyword_needed(pair):
438
+ keyword, _ = pair
439
+ return keyword in requested_keywords
440
+
441
+ keywords = dict(filter(keyword_needed, keywords.items()))
442
+ location = os.path.abspath(location.format(**keywords))
443
+ return location
@@ -0,0 +1,13 @@
1
+ from tomwer.core.volume.volumefactory import VolumeFactory
2
+ from typing import Any
3
+
4
+
5
+ def volume_identifier_to_volume(volume_identifier: Any):
6
+ """
7
+ from a str identifier try to create a volume.
8
+ Mostly used when 'volume' parameter is set from ewoks. In this case we expect it to be a (string) identifier
9
+ """
10
+ if isinstance(volume_identifier, str):
11
+ return VolumeFactory.create_tomo_object_from_identifier(volume_identifier)
12
+ else:
13
+ return volume_identifier
@@ -49,6 +49,10 @@ class EDFVolumeIdentifier(_EDFVolumeIdentifier, DatasetIdentifier):
49
49
  ObjClass=EDFVolume,
50
50
  )
51
51
 
52
+ def long_description(self) -> str:
53
+ """used for processview header tooltip for now"""
54
+ return self.to_str()
55
+
52
56
 
53
57
  class EDFVolume(_EDFVolume, TomwerVolumeBase, Dataset):
54
58
  @staticmethod
@@ -69,6 +69,10 @@ class HDF5VolumeIdentifier(_HDF5VolumeIdentifier, DatasetIdentifier):
69
69
  raise ValueError("expects to get a data_path")
70
70
  return HDF5VolumeIdentifier(object=HDF5Volume, hdf5_file=hdf5_file, entry=entry)
71
71
 
72
+ def long_description(self) -> str:
73
+ """used for processview header tooltip for now"""
74
+ return self.to_str()
75
+
72
76
 
73
77
  class HDF5Volume(_HDF5Volume, TomwerVolumeBase, Dataset):
74
78
  @staticmethod
@@ -51,6 +51,10 @@ class JP2KVolumeIdentifier(_JP2KVolumeIdentifier, DatasetIdentifier):
51
51
  ObjClass=JP2KVolume,
52
52
  )
53
53
 
54
+ def long_description(self) -> str:
55
+ """used for processview header tooltip for now"""
56
+ return self.to_str()
57
+
54
58
 
55
59
  class JP2KVolume(_JP2KVolume, TomwerVolumeBase, Dataset):
56
60
  @staticmethod
@@ -34,6 +34,10 @@ from tomoscan.esrf.identifier.rawidentifier import (
34
34
  RawVolumeIdentifier as _RawVolumeIdentifier,
35
35
  )
36
36
  from processview.core.dataset import DatasetIdentifier, Dataset
37
+ from urllib.parse import urlparse
38
+ from tomoscan.esrf.identifier.url_utils import (
39
+ split_path,
40
+ )
37
41
 
38
42
 
39
43
  class RawVolumeIdentifier(_RawVolumeIdentifier, DatasetIdentifier):
@@ -45,11 +49,24 @@ class RawVolumeIdentifier(_RawVolumeIdentifier, DatasetIdentifier):
45
49
 
46
50
  @staticmethod
47
51
  def from_str(identifier):
48
- return _RawVolumeIdentifier._from_str_to_single_frame_identifier(
49
- identifier=identifier,
50
- SingleFrameIdentifierClass=RawVolumeIdentifier,
51
- ObjClass=RawVolume,
52
- )
52
+ info = urlparse(identifier)
53
+ paths = split_path(info.path)
54
+ if len(paths) == 1:
55
+ vol_file = paths[0]
56
+ tomo_type = None
57
+ elif len(paths) == 2:
58
+ tomo_type, vol_file = paths
59
+ else:
60
+ raise ValueError("Failed to parse path string:", info.path)
61
+ if tomo_type is not None and tomo_type != RawVolumeIdentifier.TOMO_TYPE:
62
+ raise TypeError(
63
+ f"provided identifier fits {tomo_type} and not {RawVolumeIdentifier.TOMO_TYPE}"
64
+ )
65
+ return RawVolumeIdentifier(object=RawVolume, file_path=vol_file)
66
+
67
+ def long_description(self) -> str:
68
+ """used for processview header tooltip for now"""
69
+ return self.to_str()
53
70
 
54
71
 
55
72
  class RawVolume(_RawVolume, TomwerVolumeBase, Dataset):
@@ -54,6 +54,10 @@ class TIFFVolumeIdentifier(_TIFFVolumeIdentifier, DatasetIdentifier):
54
54
  ObjClass=TIFFVolume,
55
55
  )
56
56
 
57
+ def long_description(self) -> str:
58
+ """used for processview header tooltip for now"""
59
+ return self.to_str()
60
+
57
61
 
58
62
  class MultiTiffVolumeIdentifier(_MultiTiffVolumeIdentifier, DatasetIdentifier):
59
63
  def __init__(self, object, tiff_file):
@@ -3,14 +3,12 @@ from tomwer.core.tomwer_object import TomwerObject
3
3
 
4
4
 
5
5
  class TomwerVolumeBase(TomwerObject):
6
- def get_identifier(self):
7
- return self.get_identifier()
8
-
9
6
  def _clear_heavy_cache(self):
10
7
  """util user"""
11
8
  self.data = None
12
9
  self.metadata = None
13
10
 
11
+ @staticmethod
14
12
  def format_output_location(location: str, volume):
15
13
  if not isinstance(volume, TomwerVolumeBase):
16
14
  raise TypeError(
@@ -20,20 +18,29 @@ class TomwerVolumeBase(TomwerObject):
20
18
  keywords = {
21
19
  "volume_data_parent_folder": volume.volume_data_parent_folder(),
22
20
  }
23
- for keyword, value in keywords.items():
24
- if value is None:
25
- continue
26
- try:
27
- location = location.format(**{keyword: value})
28
- except KeyError:
29
- pass
21
+
22
+ # filter necessary keywords
23
+ def get_necessary_keywords():
24
+ import string
25
+
26
+ formatter = string.Formatter()
27
+ return [field for _, field, _, _ in formatter.parse(location) if field]
28
+
29
+ requested_keywords = get_necessary_keywords()
30
+
31
+ def keyword_needed(pair):
32
+ keyword, _ = pair
33
+ return keyword in requested_keywords
34
+
35
+ keywords = dict(filter(keyword_needed, keywords.items()))
36
+ location = os.path.abspath(location.format(**keywords))
30
37
  return location
31
38
 
32
39
  def volume_data_parent_folder(self):
33
- if self.data_url is None:
40
+ if self.data_url is None: # pylint: disable=E1101
34
41
  raise ValueError("data_url doesn't exists")
35
42
  else:
36
- return os.path.dirname(self.data_url.file_path())
43
+ return os.path.dirname(self.data_url.file_path()) # pylint: disable=E1101
37
44
 
38
45
  def __str__(self) -> str:
39
46
  try:
@@ -28,6 +28,7 @@ __license__ = "MIT"
28
28
  __date__ = "13/07/2022"
29
29
 
30
30
 
31
+ from typing import Optional
31
32
  from urllib.parse import urlparse
32
33
  from typing import Union
33
34
  from tomoscan.factory import Factory as _oVolumeFactory
@@ -60,6 +61,22 @@ _logger = logging.getLogger(__name__)
60
61
 
61
62
 
62
63
  class VolumeFactory(_oVolumeFactory):
64
+ @staticmethod
65
+ def from_identifier_to_vol_urls(identifier) -> Optional[tuple]:
66
+ """
67
+ convert an identifier to a volume
68
+ and return all the existing url of this volume
69
+ """
70
+ try:
71
+ vol = VolumeFactory.create_tomo_object_from_identifier(
72
+ identifier=identifier
73
+ )
74
+ except Exception as e:
75
+ _logger.error(e)
76
+ return None
77
+ else:
78
+ return tuple(vol.browse_data_urls())
79
+
63
80
  @docstring(_oVolumeFactory.create_tomo_object_from_identifier)
64
81
  @staticmethod
65
82
  def create_tomo_object_from_identifier(identifier: Union[str, BaseIdentifier]):
@@ -74,7 +91,9 @@ class VolumeFactory(_oVolumeFactory):
74
91
  :rtype: tomwer.core.scan.scanbase.TomwerScanBase
75
92
  :raises: ValueError if scan_path is not containing a scan
76
93
  """
77
- if not isinstance(identifier, (str, BaseIdentifier)):
94
+ if isinstance(identifier, BaseIdentifier):
95
+ identifier = identifier.to_str()
96
+ elif not isinstance(identifier, str):
78
97
  raise TypeError(
79
98
  f"identifier is expected to be a str or an instance of {BaseIdentifier} not {type(identifier)}"
80
99
  )
@@ -162,7 +162,7 @@ class SlurmSettingsWidget(qt.QWidget):
162
162
  self._nCores.setValue(SlurmSettings.N_CORES_PER_TASK)
163
163
  self._nWorkers.setValue(SlurmSettings.N_TASKS)
164
164
  self._memory.setValue(SlurmSettings.MEMORY_PER_WORKER)
165
- self._queue.setText(SlurmSettings.PARTIION)
165
+ self._queue.setText(SlurmSettings.PARTITION)
166
166
  self._nGpu.setValue(SlurmSettings.N_GPUS_PER_WORKER)
167
167
  self._jobName.setText(SlurmSettings.PROJECT_NAME)
168
168
  self._wallTimeQLE.setText(SlurmSettings.DEFAULT_WALLTIME)
@@ -178,7 +178,6 @@ class _DatasetProcessModel(qt.QAbstractTableModel):
178
178
  return future_scan.status in self._filteredStatus
179
179
 
180
180
  def _computeUnfilteredFutureTomoObjs(self):
181
-
182
181
  i_row = 0
183
182
  self._filteredFutureTomoObjs = OrderedDict()
184
183
 
@@ -368,7 +367,6 @@ class FilterWidget(qt.QGroupBox):
368
367
  """signal emit when filter change"""
369
368
 
370
369
  def __init__(self, parent=None):
371
-
372
370
  super().__init__("show job with status", parent)
373
371
  self.setLayout(qt.QHBoxLayout())
374
372
  # spacer
@@ -31,7 +31,7 @@ from tomwer.gui.reconstruction.nabu.slurm import SlurmSettingsWidget
31
31
  from tomwer.core.settings import SlurmSettings
32
32
  from silx.gui.utils.testutils import TestCaseQt
33
33
  from silx.gui import qt
34
- from tomwer.test.utils import skip_gui_test
34
+ from tomwer.tests.utils import skip_gui_test
35
35
  import pytest
36
36
 
37
37
 
@@ -54,7 +54,7 @@ class TestSlurmWidget(TestCaseQt):
54
54
  "cpu-per-task": SlurmSettings.N_CORES_PER_TASK,
55
55
  "n_tasks": SlurmSettings.N_TASKS,
56
56
  "memory": SlurmSettings.MEMORY_PER_WORKER,
57
- "partition": SlurmSettings.PARTIION,
57
+ "partition": SlurmSettings.PARTITION,
58
58
  "n_gpus": SlurmSettings.N_GPUS_PER_WORKER,
59
59
  }
60
60
  assert dict_res == expected_dict, f"{dict_res} vs {expected_dict}"
@@ -66,6 +66,7 @@ from nxtomomill.io.config import TomoHDF5Config as HDF5Config
66
66
  from nxtomomill.io.config import TomoEDFConfig as EDFConfig
67
67
  from nxtomomill.io import generate_default_edf_config
68
68
  from nxtomomill.io import generate_default_h5_config
69
+ from tomwer.gui.utils.qt_utils import block_signals
69
70
 
70
71
  logger = logging.getLogger(__name__)
71
72
 
@@ -222,9 +223,6 @@ class _NXtomomillConfigFileDialog(qt.QDialog):
222
223
  def accept(self):
223
224
  self.hide()
224
225
 
225
- def _createDefaultConfigFile(self):
226
- raise NotImplementedError
227
-
228
226
  def _createConfigFileSelector(self):
229
227
  raise NotImplementedError
230
228
 
@@ -245,7 +243,7 @@ class BlissHDF5DataListDialog(_DataListDialog):
245
243
  def createDataList(self):
246
244
  return BlissScanList(self)
247
245
 
248
- def _callbackAddPath(self):
246
+ def _callbackAddPath(self): # pragma: no cover
249
247
  """ """
250
248
  dialog = qt.QFileDialog(self)
251
249
  dialog.setNameFilters(["HDF5 file *.h5 *.hdf5 *.nx *.nexus", "nxs"])
@@ -280,7 +278,7 @@ class EDFDataListDialog(_DataListDialog):
280
278
  def createDataList(self):
281
279
  return EDFDataList(self)
282
280
 
283
- def _callbackAddPath(self):
281
+ def _callbackAddPath(self): # pragma: no cover
284
282
  """ """
285
283
  dialog = qt.QFileDialog(self)
286
284
  dialog.setFileMode(qt.QFileDialog.DirectoryOnly)
@@ -300,7 +298,6 @@ class EDFDataListDialog(_DataListDialog):
300
298
 
301
299
 
302
300
  class _RawDataListMainWindow(qt.QMainWindow):
303
-
304
301
  sigNXTomoCFGFileChanged = qt.Signal(str)
305
302
  """signal emitted when the configuration file change"""
306
303
 
@@ -409,14 +406,14 @@ class _RawDataListMainWindow(qt.QMainWindow):
409
406
  else:
410
407
  return config
411
408
 
412
- def createNXtomomillConfigFileDialog(self):
409
+ def createNXtomomillConfigFileDialog(self): # pragma: no cover
413
410
  file_dialog = qt.QFileDialog()
414
411
  file_dialog.setAcceptMode(qt.QFileDialog.AcceptSave)
415
412
  file_dialog.setWindowTitle("Select file path to save configuration file")
416
413
  file_dialog.setNameFilters(
417
414
  [
418
415
  "Any file (*)",
419
- "Configuration file (*.txt *.cfg *.conf)",
416
+ "Configuration file (*.txt *.cfg *.conf *.config)",
420
417
  ]
421
418
  )
422
419
  file_dialog.setFileMode(qt.QFileDialog.AnyFile)
@@ -443,7 +440,7 @@ class BlissHDF5DataListMainWindow(_RawDataListMainWindow):
443
440
  **kwargs,
444
441
  )
445
442
 
446
- def _createNewConfigFile(self):
443
+ def _createNewConfigFile(self): # pragma: no cover
447
444
  file_dialog = self.createNXtomomillConfigFileDialog()
448
445
  if file_dialog.exec_():
449
446
  files_selected = file_dialog.selectedFiles()
@@ -478,7 +475,7 @@ class EDFDataListMainWindow(_RawDataListMainWindow):
478
475
  **kwargs,
479
476
  )
480
477
 
481
- def _createNewConfigFile(self):
478
+ def _createNewConfigFile(self): # pragma: no cover
482
479
  file_dialog = self.createNXtomomillConfigFileDialog()
483
480
  if file_dialog.exec_():
484
481
  files_selected = file_dialog.selectedFiles()
@@ -499,7 +496,7 @@ class GenericScanListDialog(_DataListDialog):
499
496
  def createDataList(self):
500
497
  return GenericScanList(self)
501
498
 
502
- def _callbackAddPath(self):
499
+ def _callbackAddPath(self): # pragma: no cover
503
500
  """ """
504
501
  dialog = QDataDialog(self, multiSelection=True)
505
502
  dialog.setNameFilters(
@@ -528,7 +525,7 @@ class VolumeListDialog(_DataListDialog):
528
525
  def createDataList(self):
529
526
  return VolumeList(self)
530
527
 
531
- def _callbackAddPath(self):
528
+ def _callbackAddPath(self): # pragma: no cover
532
529
  """ """
533
530
  dialog = QVolumeDialog(self)
534
531
 
@@ -544,13 +541,15 @@ class VolumeListDialog(_DataListDialog):
544
541
 
545
542
 
546
543
  class _TomwerObjectList(qt.QTableWidget):
547
-
548
544
  HEADER_NAMES = ("undefined object",)
549
545
 
550
546
  dataReady = qt.Signal(TomwerObject)
551
547
 
548
+ listChanged = qt.Signal()
549
+ """emit when containt of the list changed"""
550
+
552
551
  def __init__(self, parent):
553
- self._target = None
552
+ self._copy_target = None
554
553
  qt.QTableWidget.__init__(self, parent)
555
554
  self.setRowCount(0)
556
555
  self.setColumnCount(1)
@@ -564,12 +563,17 @@ class _TomwerObjectList(qt.QTableWidget):
564
563
  self.setAcceptDrops(True)
565
564
 
566
565
  self._myitems = OrderedDict()
566
+ # key is the TomoObject identifier and value is the QTableWidgetItem.
567
+ # Text is the identifier, QTableWidgetItem data under UserRole is the TomoObject object
567
568
 
568
569
  # QMenu
569
570
  self.menu = qt.QMenu(self)
570
571
  self._copyAction = qt.QAction("copy")
571
572
  self._copyAction.triggered.connect(self._copyRequested)
573
+ self._pasteAction = qt.QAction("paste")
574
+ self._pasteAction.triggered.connect(self._pasteRequested)
572
575
  self.menu.addAction(self._copyAction)
576
+ self.menu.addAction(self._pasteAction)
573
577
 
574
578
  def n_data(self):
575
579
  return len(self._myitems)
@@ -610,6 +614,7 @@ class _TomwerObjectList(qt.QTableWidget):
610
614
  else:
611
615
  item = self._myitems[identifier_as_str]
612
616
  self.remove_item(item)
617
+ self.listChanged.emit()
613
618
 
614
619
  def _update(self):
615
620
  tomwer_objects = [
@@ -617,9 +622,11 @@ class _TomwerObjectList(qt.QTableWidget):
617
622
  for identifier_as_str in self._myitems.keys()
618
623
  ]
619
624
  self.clear()
620
- for tomwer_object in tomwer_objects:
621
- self.add(tomwer_object)
625
+ with block_signals(self):
626
+ for tomwer_object in tomwer_objects:
627
+ self.add(tomwer_object)
622
628
  self.sortByColumn(0, self.horizontalHeader().sortIndicatorOrder())
629
+ self.listChanged.emit()
623
630
 
624
631
  def _getTomoObject(self, obj: str):
625
632
  """
@@ -667,7 +674,8 @@ class _TomwerObjectList(qt.QTableWidget):
667
674
  # in this case we will update the value. Because if the same identifier already exists at launch time
668
675
  # it will create two different objects that could be an issue.
669
676
  # this is better to have it unified
670
- self.remove(self._myitems[identifier_as_str].data(qt.Qt.UserRole))
677
+ with block_signals(self):
678
+ self.remove(self._myitems[identifier_as_str].data(qt.Qt.UserRole))
671
679
 
672
680
  item = qt.QTableWidgetItem()
673
681
  item.setText(identifier_as_str)
@@ -679,6 +687,7 @@ class _TomwerObjectList(qt.QTableWidget):
679
687
  self.setRowCount(row + 1)
680
688
  self.setItem(row, 0, item)
681
689
  self._myitems[identifier_as_str] = item
690
+ self.listChanged.emit()
682
691
  return (obj,)
683
692
 
684
693
  def setMySelection(self, datasets: tuple):
@@ -701,16 +710,18 @@ class _TomwerObjectList(qt.QTableWidget):
701
710
  def dropEvent(self, event):
702
711
  if event.mimeData().hasFormat("text/uri-list"):
703
712
  added_scans = set()
704
- for url in event.mimeData().urls():
705
- new_scans = self.add(str(url.path()))
706
- if new_scans is not None:
707
- for new_scan in new_scans:
708
- if not isinstance(new_scan, TomwerObject):
709
- raise ValueError(
710
- f"new_scan should be an instance of {TomwerObject} and not {type(new_scan)}"
711
- )
712
- added_scans.update(new_scans)
713
+ with block_signals(self):
714
+ for url in event.mimeData().urls():
715
+ new_scans = self.add(str(url.path()))
716
+ if new_scans is not None:
717
+ for new_scan in new_scans:
718
+ if not isinstance(new_scan, TomwerObject):
719
+ raise ValueError(
720
+ f"new_scan should be an instance of {TomwerObject} and not {type(new_scan)}"
721
+ )
722
+ added_scans.update(new_scans)
713
723
  self.setMySelection(added_scans)
724
+ self.listChanged.emit()
714
725
 
715
726
  def supportedDropActions(self):
716
727
  """Inherited method to redefine supported drop actions."""
@@ -744,13 +755,24 @@ class _TomwerObjectList(qt.QTableWidget):
744
755
  return item.data(qt.Qt.UserRole)
745
756
 
746
757
  def contextMenuEvent(self, event):
747
- self._target = self._datasetAt(event.pos())
748
- if self._target is not None:
749
- self.menu.exec_(event.globalPos())
758
+ self._copy_target = self._datasetAt(event.pos())
759
+ self._copyAction.setVisible(self._copy_target is not None)
760
+ self.menu.exec_(event.globalPos())
750
761
 
751
762
  def _copyRequested(self):
752
763
  clipboard = qt.QGuiApplication.clipboard()
753
- clipboard.setText(str(self._target))
764
+ if isinstance(self._copy_target, TomwerObject):
765
+ clipboard.setText(self._copy_target.get_identifier().to_str())
766
+ else:
767
+ clipboard.setText(str(self._copy_target))
768
+
769
+ def _pasteRequested(self):
770
+ clipboard = qt.QGuiApplication.clipboard()
771
+ identifier = clipboard.text()
772
+ try:
773
+ self.add(identifier)
774
+ except Exception as e:
775
+ logger.error(f"Failed to add {identifier}. Error is {e}")
754
776
 
755
777
 
756
778
  class GenericScanList(_TomwerObjectList):
@@ -762,8 +784,12 @@ class GenericScanList(_TomwerObjectList):
762
784
  """
763
785
  some rules to return a TomwerObject from an object (probably a path) from children class
764
786
  """
787
+ return self.getScanObject(obj)
788
+
789
+ @staticmethod
790
+ def getScanObject(obj):
765
791
  if not isinstance(obj, str):
766
- raise TypeError
792
+ raise TypeError(f"obj is an instance of {type(obj)} when {str} expected")
767
793
  try:
768
794
  scan_obj = ScanFactory.create_tomo_object_from_identifier(obj)
769
795
  except ValueError as e1:
@@ -915,29 +941,76 @@ class VolumeList(_TomwerObjectList):
915
941
  }
916
942
 
917
943
  def _getTomoObject(self, obj: str):
944
+ return self.getVolumeObject(obj=obj)
945
+
946
+ @staticmethod
947
+ def getVolumeObject(obj, warn=True):
948
+ """
949
+ get volume from identifier... even if not contained in the list of items (using factory)
950
+ """
918
951
  try:
919
952
  tomo_obj = VolumeFactory.create_tomo_object_from_identifier(obj)
920
953
  except Exception as e:
921
954
  try:
922
- tomo_obj = guess_volumes(obj, scheme_to_vol=self.DEFAULT_SCHEME_TO_VOL)
955
+ tomo_obj = guess_volumes(
956
+ obj, scheme_to_vol=VolumeList.DEFAULT_SCHEME_TO_VOL
957
+ )
923
958
  except Exception:
924
- logger.warning(f"Unable to create a volume from {obj}. Error is {e}")
959
+ if warn:
960
+ logger.warning(
961
+ f"Unable to create a volume from {obj}. Error is {e}"
962
+ )
925
963
  return None
926
964
  else:
965
+ # filter potential 'nabu histogram'
966
+ if tomo_obj is not None:
967
+
968
+ def is_not_histogram(vol_identifier):
969
+ return not (
970
+ hasattr(vol_identifier, "data_path")
971
+ and vol_identifier.data_path.endswith("histogram")
972
+ )
973
+
974
+ tomo_obj = tuple(filter(is_not_histogram, tomo_obj))
975
+
927
976
  if tomo_obj is None or len(tomo_obj) == 0:
928
977
  logger.warning(f"Unable to create a volume from {obj}.")
929
978
  return None
930
979
  else:
931
980
  if len(tomo_obj) > 1:
932
- logger.warning(
933
- f"more than one volume deduce from {obj}. Will only take the first one ({tomo_obj[0]})"
934
- )
981
+ if warn:
982
+ logger.warning(
983
+ f"more than one volume deduce from {obj}. Will only take the first one ({tomo_obj[0]})"
984
+ )
935
985
  return tomo_obj[0]
936
986
  else:
937
987
  return tomo_obj
938
988
 
939
989
  def getVolume(self, volume_id: str, default=None):
990
+ """
991
+ get volume from id contained in the current items, else default
992
+ """
940
993
  if volume_id in self._myitems:
941
994
  return self._myitems[volume_id].data(qt.Qt.UserRole)
942
995
  else:
943
996
  return default
997
+
998
+
999
+ class TomoObjList(_TomwerObjectList):
1000
+ HEADER_NAMES = ("tomo object",)
1001
+
1002
+ def _getTomoObject(self, obj: str):
1003
+ try:
1004
+ tomo_obj = VolumeList.getVolumeObject(obj=obj)
1005
+ except Exception:
1006
+ pass
1007
+ else:
1008
+ if tomo_obj not in (None, tuple()):
1009
+ return tomo_obj
1010
+
1011
+ try:
1012
+ tomo_obj = GenericScanList.getScanObject(obj=obj)
1013
+ except Exception:
1014
+ return None
1015
+ else:
1016
+ return tomo_obj
@@ -111,7 +111,7 @@ class DataTransfertSelector(qt.QWidget):
111
111
  if b is True:
112
112
  self.__updateFolder(None)
113
113
 
114
- def _changeFolder(self):
114
+ def _changeFolder(self): # pragma: no cover
115
115
  """Callback when folder selection is choose"""
116
116
  defaultDirectory = self._folderSelection.text()
117
117
  if os.path.isdir(defaultDirectory):
@@ -36,7 +36,6 @@ from tomwer.core.process.control.datawatcher import status
36
36
 
37
37
 
38
38
  class _DWConfigurationWidget(qt.QWidget):
39
-
40
39
  startByOldestStateChanged = qt.Signal(bool)
41
40
 
42
41
  def __init__(self, parent):
@@ -64,7 +63,6 @@ class _DWConfigurationWidget(qt.QWidget):
64
63
 
65
64
 
66
65
  class _ObservationMethodSelector(qt.QWidget):
67
-
68
66
  sigSelectionChanged = qt.Signal(tuple)
69
67
  """Return the selection made as a string and some information if needed in
70
68
  a dictionary"""