tomwer 1.0.4__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.
- orangecontrib/tomwer/tutorials/EBS_tomo_listener.ows +39 -0
- orangecontrib/tomwer/tutorials/cast_volume.ows +34 -0
- orangecontrib/tomwer/tutorials/simple_slice_reconstruction.ows +39 -0
- orangecontrib/tomwer/tutorials/simple_volume_local_reconstruction.ows +49 -0
- orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +59 -0
- orangecontrib/tomwer/tutorials/using_saaxis_to_find_cor.ows +44 -0
- orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +1 -1
- orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +14 -4
- orangecontrib/tomwer/widgets/cluster/__init__.py +1 -1
- orangecontrib/tomwer/widgets/control/DataListOW.py +12 -5
- orangecontrib/tomwer/widgets/control/DataListenerOW.py +18 -9
- orangecontrib/tomwer/widgets/control/DataSelectorOW.py +13 -6
- orangecontrib/tomwer/widgets/control/DataTransfertOW.py +4 -5
- orangecontrib/tomwer/widgets/control/DataValidatorOW.py +8 -4
- orangecontrib/tomwer/widgets/control/DataWatcherOW.py +4 -6
- orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +49 -62
- orangecontrib/tomwer/widgets/control/FilterOW.py +2 -4
- orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +93 -0
- orangecontrib/tomwer/widgets/control/NXTomomillOW.py +135 -128
- orangecontrib/tomwer/widgets/control/NotifierOW.py +31 -7
- orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +3 -5
- orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +85 -0
- orangecontrib/tomwer/widgets/control/VolumeSelector.py +12 -4
- orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +11 -7
- orangecontrib/tomwer/widgets/control/icons/notification.svg +4 -4
- orangecontrib/tomwer/widgets/control/icons/nxtomomill.png +0 -0
- orangecontrib/tomwer/widgets/control/icons/nxtomomill.svg +8 -5
- orangecontrib/tomwer/widgets/control/icons/tomoobjserie.png +0 -0
- orangecontrib/tomwer/widgets/control/icons/tomoobjserie.svg +138 -0
- orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +16 -4
- orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +100 -0
- orangecontrib/tomwer/widgets/edit/icons/image_key_editor.png +0 -0
- orangecontrib/tomwer/widgets/edit/icons/image_key_upgrader.png +0 -0
- orangecontrib/tomwer/widgets/edit/icons/nx_tomo_editor.png +0 -0
- orangecontrib/tomwer/widgets/edit/icons/nx_tomo_editor.svg +123 -0
- orangecontrib/tomwer/widgets/edit/test/test_dark_flat_patch.py +21 -1
- orangecontrib/tomwer/widgets/edit/test/test_image_key_editor.py +1 -1
- orangecontrib/tomwer/widgets/edit/test/test_image_key_upgrader.py +1 -1
- orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +25 -0
- orangecontrib/tomwer/widgets/other/PythonScriptOW.py +19 -10
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +20 -14
- orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +24 -10
- orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +26 -21
- orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +29 -12
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +44 -17
- orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +28 -18
- orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +24 -17
- orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +6 -6
- orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +4 -2
- orangecontrib/tomwer/widgets/reconstruction/icons/nabu_2d.png +0 -0
- orangecontrib/tomwer/widgets/reconstruction/icons/nabu_2d.svg +11 -8
- orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +10 -4
- orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +69 -0
- orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +2 -4
- orangecontrib/tomwer/widgets/visualization/icons/nx_tomo_metadata_viewer.png +0 -0
- orangecontrib/tomwer/widgets/visualization/icons/nx_tomo_metadata_viewer.svg +105 -0
- tomwer/__main__.py +10 -5
- tomwer/app/canvas_launcher/config.py +10 -10
- tomwer/app/canvas_launcher/mainwindow.py +68 -6
- tomwer/app/canvas_launcher/widgetsscheme.py +1 -3
- tomwer/app/darkref.py +16 -12
- tomwer/app/imagekeyeditor.py +2 -2
- tomwer/app/imagekeyupgrader.py +104 -0
- tomwer/app/nxtomoeditor.py +103 -0
- tomwer/app/rsync.py +1 -1
- tomwer/core/cluster/cluster.py +1 -1
- tomwer/core/futureobject.py +1 -0
- tomwer/core/process/control/datalistener/datalistener.py +7 -1
- tomwer/core/process/control/datalistener/rpcserver.py +3 -3
- tomwer/core/process/control/datawatcher/datawatcher.py +18 -18
- tomwer/core/process/control/datawatcher/datawatcherobserver.py +5 -8
- tomwer/core/process/control/datawatcher/datawatcherprocess.py +2 -3
- tomwer/core/process/control/datawatcher/edfdwprocess.py +2 -2
- tomwer/core/process/control/nxtomomill.py +33 -58
- tomwer/core/process/control/scanlist.py +2 -1
- tomwer/core/process/control/scanselector.py +7 -0
- tomwer/core/process/control/scantransfer.py +9 -18
- tomwer/core/process/control/scanvalidator.py +6 -5
- tomwer/core/process/control/singletomoobj.py +2 -1
- tomwer/core/process/control/timer.py +2 -1
- tomwer/core/process/control/tomoobjserie.py +8 -0
- tomwer/core/process/control/volumeselector.py +2 -1
- tomwer/core/process/control/volumesymlink.py +2 -1
- tomwer/core/process/edit/darkflatpatch.py +2 -1
- tomwer/core/process/edit/imagekeyeditor.py +4 -3
- tomwer/core/process/reconstruction/axis/axis.py +29 -32
- tomwer/core/process/reconstruction/axis/mode.py +3 -2
- tomwer/core/process/reconstruction/axis/params.py +35 -16
- tomwer/core/process/reconstruction/darkref/darkrefs.py +90 -707
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +44 -16
- tomwer/core/process/reconstruction/darkref/params.py +62 -67
- tomwer/core/process/reconstruction/lamino/tofu.py +1 -1
- tomwer/core/process/reconstruction/nabu/castvolume.py +21 -26
- tomwer/core/process/reconstruction/nabu/nabucommon.py +36 -38
- tomwer/core/process/reconstruction/nabu/nabuscores.py +28 -13
- tomwer/core/process/reconstruction/nabu/nabuslices.py +41 -14
- tomwer/core/process/reconstruction/nabu/nabuvolume.py +21 -12
- tomwer/core/process/reconstruction/nabu/utils.py +12 -1
- tomwer/core/process/reconstruction/normalization/normalization.py +9 -8
- tomwer/core/process/reconstruction/saaxis/saaxis.py +46 -20
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +38 -12
- tomwer/core/process/reconstruction/test/__init__.py +0 -39
- tomwer/core/process/reconstruction/test/test_axis_params.py +25 -3
- tomwer/core/process/reconstruction/test/test_darkref_copy.py +117 -1
- tomwer/core/process/script/python.py +16 -12
- tomwer/core/process/task.py +3 -7
- tomwer/core/process/test/test_axis.py +1 -1
- tomwer/core/process/test/test_dark_and_flat.py +41 -111
- tomwer/core/process/test/test_data_listener.py +0 -29
- tomwer/core/process/test/test_data_transfer.py +10 -14
- tomwer/core/process/test/test_nabu.py +1 -1
- tomwer/core/process/test/test_normalization.py +1 -1
- tomwer/core/process/visualization/liveslice.py +6 -0
- tomwer/core/scan/blissscan.py +37 -2
- tomwer/core/scan/edfscan.py +14 -4
- tomwer/core/scan/hdf5scan.py +10 -4
- tomwer/core/scan/scanbase.py +35 -29
- tomwer/core/scan/scanfactory.py +3 -17
- tomwer/core/scan/test/test_h5.py +1 -1
- tomwer/core/scan/test/test_process_registration.py +0 -11
- tomwer/core/scan/test/test_scan.py +32 -30
- tomwer/core/settings.py +2 -2
- tomwer/core/test/test_utils.py +1 -1
- tomwer/core/tomwer_object.py +19 -0
- tomwer/core/utils/__init__.py +0 -45
- tomwer/core/utils/char.py +2 -0
- tomwer/core/utils/gpu.py +5 -5
- tomwer/core/utils/nxtomoutils.py +2 -2
- tomwer/core/utils/scanutils.py +50 -0
- tomwer/core/utils/volumeutils.py +13 -0
- tomwer/core/volume/edfvolume.py +4 -0
- tomwer/core/volume/hdf5volume.py +4 -0
- tomwer/core/volume/jp2kvolume.py +4 -0
- tomwer/core/volume/rawvolume.py +4 -0
- tomwer/core/volume/tiffvolume.py +4 -0
- tomwer/core/volume/volumebase.py +19 -12
- tomwer/core/volume/volumefactory.py +20 -1
- tomwer/gui/cluster/slurm.py +1 -1
- tomwer/gui/cluster/test/test_cluster.py +2 -2
- tomwer/gui/control/datalist.py +109 -34
- tomwer/gui/control/datatransfert.py +1 -1
- tomwer/gui/control/datawatcher/datawatcher.py +23 -13
- tomwer/gui/control/datawatcher/datawatcherobserver.py +1 -1
- tomwer/gui/control/observations.py +0 -3
- tomwer/gui/control/selectorwidgetbase.py +42 -11
- tomwer/gui/control/serie/seriecreator.py +967 -0
- tomwer/{web/__init__.py → gui/control/serie/seriewaiter.py} +5 -7
- tomwer/gui/control/singletomoobj.py +15 -3
- tomwer/gui/control/test/test_datalist.py +1 -1
- tomwer/gui/control/test/test_datalistener.py +1 -1
- tomwer/gui/control/test/test_inputwidget.py +1 -1
- tomwer/gui/control/test/test_process_manager.py +1 -13
- tomwer/gui/control/test/test_scanselector.py +1 -1
- tomwer/gui/control/test/test_scanvalidator.py +1 -1
- tomwer/gui/control/test/test_single_tomo_obj.py +1 -1
- tomwer/gui/control/test/test_volume_dialog.py +19 -7
- tomwer/gui/control/test/test_volumeselector.py +4 -4
- tomwer/gui/debugtools/datasetgenerator.py +1 -8
- tomwer/gui/edit/dkrfpatch.py +2 -2
- tomwer/gui/edit/imagekeyeditor.py +12 -9
- tomwer/gui/edit/nxtomoeditor.py +475 -0
- tomwer/gui/edit/test/test_dkrf_patch.py +2 -14
- tomwer/gui/edit/test/test_image_key_editor.py +2 -2
- tomwer/gui/edit/test/test_nx_editor.py +155 -0
- tomwer/gui/qfolderdialog.py +11 -0
- tomwer/gui/reconstruction/axis/CompareImages.py +27 -29
- tomwer/gui/reconstruction/axis/axis.py +2 -0
- tomwer/gui/reconstruction/axis/radioaxis.py +67 -11
- tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +7 -9
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +22 -24
- tomwer/gui/reconstruction/lamino/tofu/projections.py +1 -1
- tomwer/gui/reconstruction/lamino/tofu/tofu.py +3 -3
- tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +4 -4
- tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +10 -4
- tomwer/gui/reconstruction/nabu/castvolume.py +80 -11
- tomwer/gui/reconstruction/nabu/check.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/ctf.py +352 -0
- tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +0 -9
- tomwer/gui/reconstruction/nabu/nabuconfig/output.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +18 -19
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +30 -7
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +26 -13
- tomwer/gui/reconstruction/nabu/slices.py +10 -2
- tomwer/gui/reconstruction/nabu/slurm.py +1 -1
- tomwer/gui/reconstruction/nabu/volume.py +13 -7
- tomwer/gui/reconstruction/normalization/intensity.py +1 -1
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +10 -34
- tomwer/gui/reconstruction/saaxis/saaxis.py +11 -6
- tomwer/gui/reconstruction/saaxis/sliceselector.py +11 -26
- tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +13 -8
- tomwer/gui/reconstruction/scores/scoreplot.py +67 -61
- tomwer/gui/reconstruction/test/test_axis.py +2 -2
- tomwer/gui/reconstruction/test/test_lamino.py +2 -2
- tomwer/gui/reconstruction/test/test_nabu.py +14 -1
- tomwer/gui/reconstruction/test/test_saaxis.py +8 -17
- tomwer/gui/reconstruction/test/test_sadeltabeta.py +7 -13
- tomwer/gui/stackplot.py +11 -28
- tomwer/gui/test/test_axis_gui.py +4 -4
- tomwer/gui/test/test_qfolder_dialog.py +12 -0
- tomwer/gui/utils/inputwidget.py +42 -21
- tomwer/gui/utils/lineselector/lineselector.py +13 -21
- tomwer/gui/utils/scandescription.py +2 -4
- tomwer/gui/utils/slider.py +1 -102
- tomwer/gui/utils/unitsystem.py +48 -11
- tomwer/gui/visualization/dataviewer.py +24 -17
- tomwer/gui/visualization/diffviewer/diffviewer.py +2 -11
- tomwer/gui/visualization/nxtomometadata.py +21 -0
- tomwer/gui/visualization/scanoverview.py +0 -1
- tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +72 -0
- tomwer/gui/visualization/test/test_stacks.py +1 -1
- tomwer/gui/visualization/tomoobjoverview.py +49 -0
- tomwer/gui/visualization/volumeoverview.py +64 -0
- tomwer/gui/visualization/volumeviewer.py +1 -1
- tomwer/resources/gui/icons/multi-document-save.png +0 -0
- tomwer/resources/gui/icons/multi-document-save.svg +101 -0
- tomwer/resources/gui/illustrations/ctf_z1.png +0 -0
- tomwer/resources/gui/illustrations/ctf_z1.svg +471 -0
- tomwer/synctools/datalistener.py +5 -1
- tomwer/synctools/imageloaderthread.py +2 -2
- tomwer/synctools/stacks/edit/imagekeyeditor.py +1 -1
- tomwer/synctools/stacks/processingstack.py +2 -2
- tomwer/synctools/stacks/reconstruction/castvolume.py +1 -0
- tomwer/synctools/stacks/reconstruction/lamino.py +1 -3
- tomwer/synctools/stacks/reconstruction/sadeltabeta.py +0 -2
- tomwer/synctools/test/test_darkRefs.py +32 -149
- tomwer/synctools/test/test_foldertransfer.py +1 -1
- tomwer/synctools/test/test_scanstages.py +2 -2
- tomwer/tests/__init__.py +0 -0
- tomwer/tests/conftest.py +51 -0
- tomwer/{test → tests}/test_scripts.py +1 -1
- tomwer/tests/test_utils.py +10 -0
- tomwer/{test → tests}/utils/utilstest.py +0 -11
- tomwer/version.py +3 -3
- {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/METADATA +14 -16
- {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/RECORD +245 -217
- {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/WHEEL +1 -1
- {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/entry_points.txt +6 -0
- orangecontrib/tomwer/setup.py +0 -45
- orangecontrib/tomwer/widgets/setup.py +0 -49
- tomwer/app/process.py +0 -153
- tomwer/core/process/reconstruction/nabu/slurm.py +0 -36
- tomwer/core/process/reconstruction/utils/nabu_slice_exec.py +0 -10
- tomwer/core/utils/laminoutils.py +0 -80
- tomwer/gui/utils/lineselector/lineselection.py +0 -76
- tomwer/setup.py +0 -52
- tomwer/web/client.py +0 -43
- tomwer/web/config.py +0 -36
- tomwer/web/test/test_graylog_connection.py +0 -59
- {tomwer/test → orangecontrib/tomwer/tutorials}/__init__.py +0 -0
- /tomwer/{web/test → gui/control/serie}/__init__.py +0 -0
- /tomwer/{test → tests}/utils/__init__.py +0 -0
- /tomwer-1.0.4-py3.8-nspkg.pth → /tomwer-1.1.0-py3.9-nspkg.pth +0 -0
- {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/LICENSE +0 -0
- {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/namespace_packages.txt +0 -0
- {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/top_level.txt +0 -0
tomwer/core/utils/scanutils.py
CHANGED
@@ -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
|
tomwer/core/volume/edfvolume.py
CHANGED
@@ -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
|
tomwer/core/volume/hdf5volume.py
CHANGED
@@ -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
|
tomwer/core/volume/jp2kvolume.py
CHANGED
@@ -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
|
tomwer/core/volume/rawvolume.py
CHANGED
@@ -64,6 +64,10 @@ class RawVolumeIdentifier(_RawVolumeIdentifier, DatasetIdentifier):
|
|
64
64
|
)
|
65
65
|
return RawVolumeIdentifier(object=RawVolume, file_path=vol_file)
|
66
66
|
|
67
|
+
def long_description(self) -> str:
|
68
|
+
"""used for processview header tooltip for now"""
|
69
|
+
return self.to_str()
|
70
|
+
|
67
71
|
|
68
72
|
class RawVolume(_RawVolume, TomwerVolumeBase, Dataset):
|
69
73
|
@staticmethod
|
tomwer/core/volume/tiffvolume.py
CHANGED
@@ -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):
|
tomwer/core/volume/volumebase.py
CHANGED
@@ -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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
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
|
)
|
tomwer/gui/cluster/slurm.py
CHANGED
@@ -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.
|
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)
|
@@ -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.
|
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.
|
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}"
|
tomwer/gui/control/datalist.py
CHANGED
@@ -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)
|
@@ -408,14 +406,14 @@ class _RawDataListMainWindow(qt.QMainWindow):
|
|
408
406
|
else:
|
409
407
|
return config
|
410
408
|
|
411
|
-
def createNXtomomillConfigFileDialog(self):
|
409
|
+
def createNXtomomillConfigFileDialog(self): # pragma: no cover
|
412
410
|
file_dialog = qt.QFileDialog()
|
413
411
|
file_dialog.setAcceptMode(qt.QFileDialog.AcceptSave)
|
414
412
|
file_dialog.setWindowTitle("Select file path to save configuration file")
|
415
413
|
file_dialog.setNameFilters(
|
416
414
|
[
|
417
415
|
"Any file (*)",
|
418
|
-
"Configuration file (*.txt *.cfg *.conf)",
|
416
|
+
"Configuration file (*.txt *.cfg *.conf *.config)",
|
419
417
|
]
|
420
418
|
)
|
421
419
|
file_dialog.setFileMode(qt.QFileDialog.AnyFile)
|
@@ -442,7 +440,7 @@ class BlissHDF5DataListMainWindow(_RawDataListMainWindow):
|
|
442
440
|
**kwargs,
|
443
441
|
)
|
444
442
|
|
445
|
-
def _createNewConfigFile(self):
|
443
|
+
def _createNewConfigFile(self): # pragma: no cover
|
446
444
|
file_dialog = self.createNXtomomillConfigFileDialog()
|
447
445
|
if file_dialog.exec_():
|
448
446
|
files_selected = file_dialog.selectedFiles()
|
@@ -477,7 +475,7 @@ class EDFDataListMainWindow(_RawDataListMainWindow):
|
|
477
475
|
**kwargs,
|
478
476
|
)
|
479
477
|
|
480
|
-
def _createNewConfigFile(self):
|
478
|
+
def _createNewConfigFile(self): # pragma: no cover
|
481
479
|
file_dialog = self.createNXtomomillConfigFileDialog()
|
482
480
|
if file_dialog.exec_():
|
483
481
|
files_selected = file_dialog.selectedFiles()
|
@@ -498,7 +496,7 @@ class GenericScanListDialog(_DataListDialog):
|
|
498
496
|
def createDataList(self):
|
499
497
|
return GenericScanList(self)
|
500
498
|
|
501
|
-
def _callbackAddPath(self):
|
499
|
+
def _callbackAddPath(self): # pragma: no cover
|
502
500
|
""" """
|
503
501
|
dialog = QDataDialog(self, multiSelection=True)
|
504
502
|
dialog.setNameFilters(
|
@@ -527,7 +525,7 @@ class VolumeListDialog(_DataListDialog):
|
|
527
525
|
def createDataList(self):
|
528
526
|
return VolumeList(self)
|
529
527
|
|
530
|
-
def _callbackAddPath(self):
|
528
|
+
def _callbackAddPath(self): # pragma: no cover
|
531
529
|
""" """
|
532
530
|
dialog = QVolumeDialog(self)
|
533
531
|
|
@@ -547,8 +545,11 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
547
545
|
|
548
546
|
dataReady = qt.Signal(TomwerObject)
|
549
547
|
|
548
|
+
listChanged = qt.Signal()
|
549
|
+
"""emit when containt of the list changed"""
|
550
|
+
|
550
551
|
def __init__(self, parent):
|
551
|
-
self.
|
552
|
+
self._copy_target = None
|
552
553
|
qt.QTableWidget.__init__(self, parent)
|
553
554
|
self.setRowCount(0)
|
554
555
|
self.setColumnCount(1)
|
@@ -562,12 +563,17 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
562
563
|
self.setAcceptDrops(True)
|
563
564
|
|
564
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
|
565
568
|
|
566
569
|
# QMenu
|
567
570
|
self.menu = qt.QMenu(self)
|
568
571
|
self._copyAction = qt.QAction("copy")
|
569
572
|
self._copyAction.triggered.connect(self._copyRequested)
|
573
|
+
self._pasteAction = qt.QAction("paste")
|
574
|
+
self._pasteAction.triggered.connect(self._pasteRequested)
|
570
575
|
self.menu.addAction(self._copyAction)
|
576
|
+
self.menu.addAction(self._pasteAction)
|
571
577
|
|
572
578
|
def n_data(self):
|
573
579
|
return len(self._myitems)
|
@@ -608,6 +614,7 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
608
614
|
else:
|
609
615
|
item = self._myitems[identifier_as_str]
|
610
616
|
self.remove_item(item)
|
617
|
+
self.listChanged.emit()
|
611
618
|
|
612
619
|
def _update(self):
|
613
620
|
tomwer_objects = [
|
@@ -615,9 +622,11 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
615
622
|
for identifier_as_str in self._myitems.keys()
|
616
623
|
]
|
617
624
|
self.clear()
|
618
|
-
|
619
|
-
|
625
|
+
with block_signals(self):
|
626
|
+
for tomwer_object in tomwer_objects:
|
627
|
+
self.add(tomwer_object)
|
620
628
|
self.sortByColumn(0, self.horizontalHeader().sortIndicatorOrder())
|
629
|
+
self.listChanged.emit()
|
621
630
|
|
622
631
|
def _getTomoObject(self, obj: str):
|
623
632
|
"""
|
@@ -665,7 +674,8 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
665
674
|
# in this case we will update the value. Because if the same identifier already exists at launch time
|
666
675
|
# it will create two different objects that could be an issue.
|
667
676
|
# this is better to have it unified
|
668
|
-
|
677
|
+
with block_signals(self):
|
678
|
+
self.remove(self._myitems[identifier_as_str].data(qt.Qt.UserRole))
|
669
679
|
|
670
680
|
item = qt.QTableWidgetItem()
|
671
681
|
item.setText(identifier_as_str)
|
@@ -677,6 +687,7 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
677
687
|
self.setRowCount(row + 1)
|
678
688
|
self.setItem(row, 0, item)
|
679
689
|
self._myitems[identifier_as_str] = item
|
690
|
+
self.listChanged.emit()
|
680
691
|
return (obj,)
|
681
692
|
|
682
693
|
def setMySelection(self, datasets: tuple):
|
@@ -699,16 +710,18 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
699
710
|
def dropEvent(self, event):
|
700
711
|
if event.mimeData().hasFormat("text/uri-list"):
|
701
712
|
added_scans = set()
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
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)
|
711
723
|
self.setMySelection(added_scans)
|
724
|
+
self.listChanged.emit()
|
712
725
|
|
713
726
|
def supportedDropActions(self):
|
714
727
|
"""Inherited method to redefine supported drop actions."""
|
@@ -742,13 +755,24 @@ class _TomwerObjectList(qt.QTableWidget):
|
|
742
755
|
return item.data(qt.Qt.UserRole)
|
743
756
|
|
744
757
|
def contextMenuEvent(self, event):
|
745
|
-
self.
|
746
|
-
|
747
|
-
|
758
|
+
self._copy_target = self._datasetAt(event.pos())
|
759
|
+
self._copyAction.setVisible(self._copy_target is not None)
|
760
|
+
self.menu.exec_(event.globalPos())
|
748
761
|
|
749
762
|
def _copyRequested(self):
|
750
763
|
clipboard = qt.QGuiApplication.clipboard()
|
751
|
-
|
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}")
|
752
776
|
|
753
777
|
|
754
778
|
class GenericScanList(_TomwerObjectList):
|
@@ -760,8 +784,12 @@ class GenericScanList(_TomwerObjectList):
|
|
760
784
|
"""
|
761
785
|
some rules to return a TomwerObject from an object (probably a path) from children class
|
762
786
|
"""
|
787
|
+
return self.getScanObject(obj)
|
788
|
+
|
789
|
+
@staticmethod
|
790
|
+
def getScanObject(obj):
|
763
791
|
if not isinstance(obj, str):
|
764
|
-
raise TypeError
|
792
|
+
raise TypeError(f"obj is an instance of {type(obj)} when {str} expected")
|
765
793
|
try:
|
766
794
|
scan_obj = ScanFactory.create_tomo_object_from_identifier(obj)
|
767
795
|
except ValueError as e1:
|
@@ -913,29 +941,76 @@ class VolumeList(_TomwerObjectList):
|
|
913
941
|
}
|
914
942
|
|
915
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
|
+
"""
|
916
951
|
try:
|
917
952
|
tomo_obj = VolumeFactory.create_tomo_object_from_identifier(obj)
|
918
953
|
except Exception as e:
|
919
954
|
try:
|
920
|
-
tomo_obj = guess_volumes(
|
955
|
+
tomo_obj = guess_volumes(
|
956
|
+
obj, scheme_to_vol=VolumeList.DEFAULT_SCHEME_TO_VOL
|
957
|
+
)
|
921
958
|
except Exception:
|
922
|
-
|
959
|
+
if warn:
|
960
|
+
logger.warning(
|
961
|
+
f"Unable to create a volume from {obj}. Error is {e}"
|
962
|
+
)
|
923
963
|
return None
|
924
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
|
+
|
925
976
|
if tomo_obj is None or len(tomo_obj) == 0:
|
926
977
|
logger.warning(f"Unable to create a volume from {obj}.")
|
927
978
|
return None
|
928
979
|
else:
|
929
980
|
if len(tomo_obj) > 1:
|
930
|
-
|
931
|
-
|
932
|
-
|
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
|
+
)
|
933
985
|
return tomo_obj[0]
|
934
986
|
else:
|
935
987
|
return tomo_obj
|
936
988
|
|
937
989
|
def getVolume(self, volume_id: str, default=None):
|
990
|
+
"""
|
991
|
+
get volume from id contained in the current items, else default
|
992
|
+
"""
|
938
993
|
if volume_id in self._myitems:
|
939
994
|
return self._myitems[volume_id].data(qt.Qt.UserRole)
|
940
995
|
else:
|
941
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):
|