tomwer 1.4.19__py3-none-any.whl → 1.5.0rc0__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/simple_volume_local_reconstruction.ows +11 -8
- orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +12 -9
- orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +1 -1
- orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +21 -10
- tomwer/app/reducedarkflat.py +2 -2
- tomwer/core/process/edit/imagekeyeditor.py +4 -6
- tomwer/core/process/edit/nxtomoeditor.py +58 -20
- tomwer/core/process/output.py +6 -5
- tomwer/core/process/reconstruction/axis/anglemode.py +2 -2
- tomwer/core/process/reconstruction/axis/axis.py +1 -0
- tomwer/core/process/reconstruction/darkref/darkrefs.py +2 -2
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +1 -1
- tomwer/core/process/reconstruction/darkref/params.py +1 -1
- tomwer/core/process/reconstruction/nabu/castvolume.py +4 -1
- tomwer/core/process/reconstruction/nabu/helical.py +3 -1
- tomwer/core/process/reconstruction/nabu/nabuscores.py +1 -1
- tomwer/core/process/reconstruction/nabu/nabuslices.py +4 -4
- tomwer/core/process/reconstruction/nabu/plane.py +2 -2
- tomwer/core/process/reconstruction/nabu/test/test_castvolume.py +2 -0
- tomwer/core/process/reconstruction/nabu/utils.py +15 -14
- tomwer/core/process/reconstruction/normalization/params.py +1 -1
- tomwer/core/process/reconstruction/output.py +2 -2
- tomwer/core/process/reconstruction/tests/test_axis.py +1 -1
- tomwer/core/process/stitching/metadataholder.py +5 -5
- tomwer/core/process/stitching/nabustitcher.py +1 -4
- tomwer/core/scan/edfscan.py +3 -3
- tomwer/core/scan/nxtomoscan.py +3 -3
- tomwer/core/scan/scanbase.py +2 -2
- tomwer/core/tomwer_object.py +1 -1
- tomwer/core/utils/nxtomoutils.py +2 -2
- tomwer/core/utils/spec.py +6 -3
- tomwer/gui/control/datadiscovery.py +1 -1
- tomwer/gui/control/reducedarkflatselector.py +4 -4
- tomwer/gui/edit/imagekeyeditor.py +7 -9
- tomwer/gui/edit/nxtomoeditor.py +420 -112
- tomwer/gui/edit/tests/test_nx_editor.py +154 -82
- tomwer/gui/reconstruction/axis/CalculationWidget.py +1 -1
- tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +12 -8
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -2
- tomwer/gui/reconstruction/nabu/castvolume.py +16 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/base.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +2 -2
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +2 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +71 -49
- tomwer/gui/reconstruction/nabu/nabuflow.py +3 -13
- tomwer/gui/reconstruction/nabu/slices.py +6 -6
- tomwer/gui/reconstruction/nabu/test/test_cast_volume.py +19 -0
- tomwer/gui/reconstruction/normalization/intensity.py +2 -2
- tomwer/gui/reconstruction/saaxis/dimensionwidget.py +71 -67
- tomwer/gui/reconstruction/scores/scoreplot.py +15 -7
- tomwer/gui/reconstruction/tests/test_saaxis.py +18 -16
- tomwer/gui/stitching/SingleAxisStitchingWidget.py +8 -8
- tomwer/gui/stitching/StitchingOptionsWidget.py +1 -1
- tomwer/gui/stitching/alignment.py +8 -8
- tomwer/gui/stitching/config/axisparams.py +2 -2
- tomwer/gui/stitching/config/output.py +1 -1
- tomwer/gui/stitching/config/stitchingstrategies.py +4 -6
- tomwer/gui/stitching/config/tomoobjdetails.py +21 -13
- tomwer/gui/stitching/normalization.py +6 -6
- tomwer/gui/stitching/tests/test_ZStitchingWindow.py +8 -1
- tomwer/gui/stitching/tests/test_preview.py +10 -7
- tomwer/gui/stitching/tests/utils.py +27 -18
- tomwer/gui/stitching/z_stitching/fineestimation.py +7 -9
- tomwer/gui/stitching/z_stitching/tests/test_raw_estimation.py +18 -7
- tomwer/gui/stitching/z_stitching/tests/test_stitching_window.py +7 -2
- tomwer/gui/utils/buttons.py +53 -35
- tomwer/gui/utils/flow.py +1 -1
- tomwer/gui/utils/unitsystem.py +44 -33
- tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
- tomwer/gui/visualization/diffviewer/shiftwidget.py +4 -6
- tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +25 -13
- tomwer/model/dataset.py +0 -0
- tomwer/tasks/reconstruction/cleardarkflat.py +42 -0
- tomwer/tests/app/test_stitching.py +1 -1
- tomwer/tests/orangecontrib/tomwer/widgets/edit/tests/test_nxtomo_editor.py +32 -20
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_nabu_widget.py +1 -1
- tomwer/version.py +3 -3
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/METADATA +8 -8
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/RECORD +84 -82
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/WHEEL +1 -1
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/entry_points.txt +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/licenses/LICENSE +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.0rc0.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,7 @@ from nabu.pipeline.config import generate_nabu_configfile, parse_nabu_config_fil
|
|
10
10
|
from nabu.pipeline.fullfield.nabu_config import (
|
11
11
|
nabu_config as nabu_fullfield_default_config,
|
12
12
|
)
|
13
|
-
from
|
13
|
+
from enum import Enum
|
14
14
|
|
15
15
|
from tomoscan.identifier import VolumeIdentifier
|
16
16
|
import tomwer.version
|
@@ -240,13 +240,13 @@ def get_multi_cor_recons_volume_identifiers(
|
|
240
240
|
return res
|
241
241
|
|
242
242
|
|
243
|
-
class _NabuMode(
|
243
|
+
class _NabuMode(Enum):
|
244
244
|
FULL_FIELD = "standard acquisition"
|
245
245
|
HALF_ACQ = "half acquisition"
|
246
246
|
# HELICAL = "helical acquisition"
|
247
247
|
|
248
248
|
|
249
|
-
class _NabuStages(
|
249
|
+
class _NabuStages(Enum):
|
250
250
|
INI = "initialization"
|
251
251
|
PRE = "pre-processing"
|
252
252
|
PHASE = "phase"
|
@@ -267,7 +267,7 @@ class _NabuStages(_Enum):
|
|
267
267
|
@staticmethod
|
268
268
|
def getProcessEnum(stage):
|
269
269
|
"""Return the process Enum associated to the stage"""
|
270
|
-
stage = _NabuStages
|
270
|
+
stage = _NabuStages(stage)
|
271
271
|
if stage is _NabuStages.INI:
|
272
272
|
raise NotImplementedError()
|
273
273
|
elif stage is _NabuStages.PRE:
|
@@ -281,7 +281,7 @@ class _NabuStages(_Enum):
|
|
281
281
|
raise NotImplementedError()
|
282
282
|
|
283
283
|
|
284
|
-
class _NabuPreprocessing(
|
284
|
+
class _NabuPreprocessing(Enum):
|
285
285
|
"""Define all the preprocessing action possible and the order they
|
286
286
|
are applied on"""
|
287
287
|
|
@@ -296,7 +296,7 @@ class _NabuPreprocessing(_Enum):
|
|
296
296
|
)
|
297
297
|
|
298
298
|
|
299
|
-
class _NabuPhase(
|
299
|
+
class _NabuPhase(Enum):
|
300
300
|
"""Define all the phase action possible and the order they
|
301
301
|
are applied on"""
|
302
302
|
|
@@ -309,7 +309,7 @@ class _NabuPhase(_Enum):
|
|
309
309
|
return (_NabuPhase.PHASE, _NabuPhase.UNSHARP_MASK, _NabuPhase.LOGARITHM)
|
310
310
|
|
311
311
|
|
312
|
-
class _NabuProcessing(
|
312
|
+
class _NabuProcessing(Enum):
|
313
313
|
"""Define all the processing action possible"""
|
314
314
|
|
315
315
|
RECONSTRUCTION = "reconstruction"
|
@@ -319,7 +319,7 @@ class _NabuProcessing(_Enum):
|
|
319
319
|
return (_NabuProcessing.RECONSTRUCTION,)
|
320
320
|
|
321
321
|
|
322
|
-
class _NabuPostProcessing(
|
322
|
+
class _NabuPostProcessing(Enum):
|
323
323
|
"""Define all the post processing action available"""
|
324
324
|
|
325
325
|
SAVE_DATA = "save"
|
@@ -329,11 +329,12 @@ class _NabuPostProcessing(_Enum):
|
|
329
329
|
return (_NabuPostProcessing.SAVE_DATA,)
|
330
330
|
|
331
331
|
|
332
|
-
class _NabuReconstructionMethods(
|
332
|
+
class _NabuReconstructionMethods(Enum):
|
333
333
|
FBP = "FBP"
|
334
|
+
MLEM = "MLEM"
|
334
335
|
|
335
336
|
|
336
|
-
class _NabuPhaseMethod(
|
337
|
+
class _NabuPhaseMethod(Enum):
|
337
338
|
"""
|
338
339
|
Nabu phase method
|
339
340
|
"""
|
@@ -354,10 +355,10 @@ class _NabuPhaseMethod(_Enum):
|
|
354
355
|
elif value.lower() == "ctf":
|
355
356
|
return _NabuPhaseMethod.CTF
|
356
357
|
else:
|
357
|
-
return
|
358
|
+
return _NabuPhaseMethod(value=value)
|
358
359
|
|
359
360
|
|
360
|
-
class _NabuFBPFilterType(
|
361
|
+
class _NabuFBPFilterType(Enum):
|
361
362
|
RAMLAK = "ramlak"
|
362
363
|
SHEPP_LOGAN = "shepp-logan"
|
363
364
|
COSINE = "cosine"
|
@@ -368,12 +369,12 @@ class _NabuFBPFilterType(_Enum):
|
|
368
369
|
HILBERT = "hilbert"
|
369
370
|
|
370
371
|
|
371
|
-
class _NabuPaddingType(
|
372
|
+
class _NabuPaddingType(Enum):
|
372
373
|
ZEROS = "zeros"
|
373
374
|
EDGES = "edges"
|
374
375
|
|
375
376
|
|
376
|
-
class RingCorrectionMethod(
|
377
|
+
class RingCorrectionMethod(Enum):
|
377
378
|
NONE = "None"
|
378
379
|
MUNCH = "munch"
|
379
380
|
VO = "vo"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
import os
|
3
3
|
import logging
|
4
|
-
from
|
4
|
+
from enum import Enum as _Enum
|
5
5
|
from tomwer.io.utils.raw_and_processed_data import (
|
6
6
|
to_processed_data_path,
|
7
7
|
)
|
@@ -30,7 +30,7 @@ class NabuOutputFileFormat(_Enum):
|
|
30
30
|
def from_value(cls, value):
|
31
31
|
if isinstance(value, str):
|
32
32
|
value = value.lstrip(".")
|
33
|
-
return
|
33
|
+
return NabuOutputFileFormat(value)
|
34
34
|
|
35
35
|
|
36
36
|
def get_file_format(file_str):
|
@@ -40,7 +40,7 @@ def test_read_x_rotation_axis_pixel_position(nxtomo_scan_360): # noqa F811
|
|
40
40
|
with h5py.File(nxtomo_scan_360.master_file, mode="a") as h5f:
|
41
41
|
h5f[x_rotation_axis_pixel_position_path] = 12.5
|
42
42
|
|
43
|
-
nxtomo_scan_360.
|
43
|
+
nxtomo_scan_360.clear_cache()
|
44
44
|
task.run()
|
45
45
|
assert nxtomo_scan_360.axis_params.absolute_cor_value == 22.5
|
46
46
|
assert nxtomo_scan_360.axis_params.relative_cor_value == 12.5
|
@@ -41,19 +41,19 @@ class StitchingMetadata:
|
|
41
41
|
if value is not None and not isinstance(
|
42
42
|
value, (float, numpy.float32, numpy.float64)
|
43
43
|
):
|
44
|
-
raise TypeError
|
44
|
+
raise TypeError(f"Invalid type for value. Got {type(value)}")
|
45
45
|
self._pixel_or_voxel_size[axis] = value
|
46
46
|
|
47
47
|
def setPxPos(self, value, axis):
|
48
48
|
if value is not None and not isinstance(value, (int, numpy.int32)):
|
49
|
-
raise TypeError
|
49
|
+
raise TypeError(f"Invalid type for value. Got {type(value)}")
|
50
50
|
self._pos_as_px[axis] = value
|
51
51
|
|
52
52
|
def setMetricPos(self, value, axis):
|
53
53
|
if value is not None and not isinstance(
|
54
54
|
value, (int, numpy.float32, numpy.float64, float)
|
55
55
|
):
|
56
|
-
raise TypeError
|
56
|
+
raise TypeError(f"Invalid type for value. Got {type(value)}")
|
57
57
|
self._pos_as_m[axis] = value
|
58
58
|
|
59
59
|
def get_raw_position_m(self, axis):
|
@@ -111,9 +111,9 @@ class StitchingMetadata:
|
|
111
111
|
return self._pixel_or_voxel_size[axis]
|
112
112
|
elif isinstance(self.tomo_obj, TomoScanBase):
|
113
113
|
if axis == 0:
|
114
|
-
return self.tomo_obj.
|
114
|
+
return self.tomo_obj.sample_y_pixel_size
|
115
115
|
elif axis in (1, 2):
|
116
|
-
return self.tomo_obj.
|
116
|
+
return self.tomo_obj.sample_x_pixel_size
|
117
117
|
else:
|
118
118
|
raise TypeError(f"axis is expected to be in (0, 1, 2). {axis} provided")
|
119
119
|
elif isinstance(self.tomo_obj, VolumeBase):
|
@@ -162,12 +162,9 @@ class StitchingPostProcAggregation(_StitchingPostProcAggregation):
|
|
162
162
|
|
163
163
|
def __init__(self, *args, **kwargs) -> None:
|
164
164
|
super().__init__(*args, **kwargs)
|
165
|
-
print("creates StitchingPostProcAggregation")
|
166
165
|
|
167
166
|
if isinstance(self.stitching_config, dict):
|
168
|
-
stitching_type = StitchingType.
|
169
|
-
self.stitching_config["stitching"]["type"]
|
170
|
-
)
|
167
|
+
stitching_type = StitchingType(self.stitching_config["stitching"]["type"])
|
171
168
|
if stitching_type is StitchingType.Z_PREPROC:
|
172
169
|
self._stitching_config = PreProcessedZStitchingConfiguration.from_dict(
|
173
170
|
self.stitching_config
|
tomwer/core/scan/edfscan.py
CHANGED
@@ -127,9 +127,9 @@ class EDFTomoScan(_tsEDFTomoScan, TomwerScanBase):
|
|
127
127
|
)
|
128
128
|
return EDFTomoScan(scan=identifier.folder)
|
129
129
|
|
130
|
-
def
|
131
|
-
_tsEDFTomoScan.
|
132
|
-
TomwerScanBase.
|
130
|
+
def clear_cache(self):
|
131
|
+
_tsEDFTomoScan.clear_cache(self)
|
132
|
+
TomwerScanBase.clear_cache(self)
|
133
133
|
|
134
134
|
@staticmethod
|
135
135
|
def directory_contains_scan(directory, src_pattern, dest_pattern):
|
tomwer/core/scan/nxtomoscan.py
CHANGED
@@ -178,9 +178,9 @@ class NXtomoScan(_tsNXtomoScan, TomwerScanBase):
|
|
178
178
|
else:
|
179
179
|
return os.path.exists(master_file + ".h5")
|
180
180
|
|
181
|
-
def
|
182
|
-
_tsNXtomoScan.
|
183
|
-
TomwerScanBase.
|
181
|
+
def clear_cache(self):
|
182
|
+
_tsNXtomoScan.clear_cache(self)
|
183
|
+
TomwerScanBase.clear_cache(self)
|
184
184
|
|
185
185
|
def is_abort(self, src_pattern, dest_pattern):
|
186
186
|
"""
|
tomwer/core/scan/scanbase.py
CHANGED
@@ -92,10 +92,10 @@ class TomwerScanBase(TomwerObject):
|
|
92
92
|
"""
|
93
93
|
raise NotImplementedError("Base class")
|
94
94
|
|
95
|
-
def
|
95
|
+
def clear_cache(self):
|
96
96
|
self._cache_proj_urls = None
|
97
97
|
self._notify_ffc_rsc_missing = True
|
98
|
-
super().
|
98
|
+
super().clear_cache()
|
99
99
|
|
100
100
|
def _flat_field_correction(
|
101
101
|
self,
|
tomwer/core/tomwer_object.py
CHANGED
tomwer/core/utils/nxtomoutils.py
CHANGED
@@ -11,12 +11,12 @@ def get_n_series(image_key_values: tuple | list, image_key_type: ImageKey) -> in
|
|
11
11
|
|
12
12
|
:param image_key_values: list or tuple of image_keys to consider. Can be integers or tomoscan.esrf.scan.hdf5scan.ImageKey
|
13
13
|
"""
|
14
|
-
image_key_type = ImageKey
|
14
|
+
image_key_type = ImageKey(image_key_type)
|
15
15
|
if image_key_type is ImageKey.INVALID:
|
16
16
|
raise ValueError(
|
17
17
|
"we can't count Invalid image keys series because those are ignored from tomoscan"
|
18
18
|
)
|
19
|
-
image_key_values = [ImageKey
|
19
|
+
image_key_values = [ImageKey(img_key) for img_key in image_key_values]
|
20
20
|
|
21
21
|
# remove invalid frames
|
22
22
|
image_key_values = numpy.array(
|
tomwer/core/utils/spec.py
CHANGED
@@ -3,14 +3,17 @@ from __future__ import annotations
|
|
3
3
|
import fileinput
|
4
4
|
import logging
|
5
5
|
import os
|
6
|
+
import pint
|
7
|
+
|
8
|
+
import fabio
|
6
9
|
|
7
|
-
import fabio.edfimage
|
8
10
|
from lxml import etree
|
9
|
-
from pyunitsystem.metricsystem import MetricSystem
|
10
11
|
|
11
12
|
|
12
13
|
_logger = logging.getLogger(__name__)
|
13
14
|
|
15
|
+
_ureg = pint.get_application_registry()
|
16
|
+
|
14
17
|
|
15
18
|
def _getInformation(scan, refFile, information, _type, aliases=None):
|
16
19
|
"""
|
@@ -258,6 +261,6 @@ def getPixelSize(scan) -> float | None:
|
|
258
261
|
value = float(ddict["IMAGE_PIXEL_SIZE_1".lower()])
|
259
262
|
# for now pixel size are stored in microns. We want to return them in meter
|
260
263
|
if value is not None:
|
261
|
-
return value *
|
264
|
+
return (value * _ureg.micrometer).to_base_units().magnitude
|
262
265
|
else:
|
263
266
|
return None
|
@@ -44,7 +44,7 @@ class ScanDiscoveryConfigWidget(qt.QGroupBox):
|
|
44
44
|
raise NotImplementedError
|
45
45
|
|
46
46
|
def setScanType(self, mode: ScanType):
|
47
|
-
mode = ScanType
|
47
|
+
mode = ScanType(mode)
|
48
48
|
if mode is ScanType.SPEC:
|
49
49
|
self._specQRB.setChecked(True)
|
50
50
|
elif mode is ScanType.BLISS:
|
@@ -287,11 +287,11 @@ class ReduceDarkFlatSelectorTableWidget(qt.QWidget):
|
|
287
287
|
h5file=url.file_path(),
|
288
288
|
path=url.data_path(),
|
289
289
|
)
|
290
|
-
for target in REDUCER_TARGET
|
291
|
-
if target in reduced_info_dict:
|
292
|
-
reduced_frames = reduced_info_dict[target]
|
290
|
+
for target in REDUCER_TARGET:
|
291
|
+
if target.value in reduced_info_dict:
|
292
|
+
reduced_frames = reduced_info_dict[target.value]
|
293
293
|
reduced_frames["reduce_frames_name"] = (
|
294
|
-
f"{target} from {url.data_path()}@{os.path.basename(url.file_path())}"
|
294
|
+
f"{target.value} from {url.data_path()}@{os.path.basename(url.file_path())}"
|
295
295
|
)
|
296
296
|
result.append(reduced_frames)
|
297
297
|
|
@@ -112,9 +112,7 @@ class ImageKeyWindow(qt.QMainWindow):
|
|
112
112
|
def setModifications(self, modifications):
|
113
113
|
self._mainWindow.clearModifcations()
|
114
114
|
image_keys_set = set(modifications.values())
|
115
|
-
image_keys_set = set(
|
116
|
-
[_ImageKey.from_value(image_key) for image_key in image_keys_set]
|
117
|
-
)
|
115
|
+
image_keys_set = set([_ImageKey(image_key) for image_key in image_keys_set])
|
118
116
|
for image_key_type in image_keys_set:
|
119
117
|
self._mainWindow.applyModifications(
|
120
118
|
modifications=modifications, new_image_key=image_key_type
|
@@ -432,7 +430,7 @@ class _ImageKeyList(qt.QTableWidget):
|
|
432
430
|
self.setItem(i_frame, 0, _item)
|
433
431
|
|
434
432
|
# current image key
|
435
|
-
current_image_key = _ImageKey
|
433
|
+
current_image_key = _ImageKey(frame.image_key)
|
436
434
|
current_image_key = self._IMAGE_KEYS_INV[current_image_key]
|
437
435
|
currentImgKeyItem = qt.QLabel(current_image_key, self)
|
438
436
|
self.setCellWidget(i_frame, 1, currentImgKeyItem)
|
@@ -442,7 +440,7 @@ class _ImageKeyList(qt.QTableWidget):
|
|
442
440
|
new_image_key = frames_new_keys[frame.index]
|
443
441
|
else:
|
444
442
|
new_image_key = frame.image_key
|
445
|
-
new_image_key = _ImageKey
|
443
|
+
new_image_key = _ImageKey(new_image_key)
|
446
444
|
new_image_key = self._IMAGE_KEYS_INV[new_image_key]
|
447
445
|
newImgKeyItem = _ImageKeyComboBox(parent=self, image_key=new_image_key)
|
448
446
|
self._imageKeyComboboxes[index] = newImgKeyItem
|
@@ -694,16 +692,16 @@ class ImageKeyUpgraderList(qt.QTableWidget):
|
|
694
692
|
self.setCellWidget(i_operation, 1, remove_button)
|
695
693
|
|
696
694
|
def addOperation(self, from_image_key: _ImageKey, to_image_key: _ImageKey):
|
697
|
-
from_image_key = _ImageKey
|
698
|
-
to_image_key = _ImageKey
|
695
|
+
from_image_key = _ImageKey(from_image_key)
|
696
|
+
to_image_key = _ImageKey(to_image_key)
|
699
697
|
|
700
698
|
self._operations[from_image_key] = to_image_key
|
701
699
|
self._update()
|
702
700
|
self.sigOperationsChanged.emit()
|
703
701
|
|
704
702
|
def removeOperation(self, from_image_key: _ImageKey, to_image_key: _ImageKey):
|
705
|
-
from_image_key = _ImageKey
|
706
|
-
to_image_key = _ImageKey
|
703
|
+
from_image_key = _ImageKey(from_image_key)
|
704
|
+
to_image_key = _ImageKey(to_image_key)
|
707
705
|
if (
|
708
706
|
from_image_key not in self._operations
|
709
707
|
or self._operations[from_image_key] != to_image_key
|