tomwer 1.3.12__py3-none-any.whl → 1.3.26__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 (34) hide show
  1. orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +1 -0
  2. orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +184 -184
  3. tomwer/app/canvas_launcher/mainwindow.py +0 -1
  4. tomwer/app/zstitching.py +0 -1
  5. tomwer/core/cluster/cluster.py +0 -9
  6. tomwer/core/process/control/datalistener/datalistener.py +4 -1
  7. tomwer/core/process/reconstruction/axis/params.py +3 -3
  8. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +34 -6
  9. tomwer/core/process/reconstruction/nabu/utils.py +4 -2
  10. tomwer/core/utils/scanutils.py +5 -1
  11. tomwer/gui/cluster/slurm.py +1 -21
  12. tomwer/gui/cluster/test/test_cluster.py +0 -1
  13. tomwer/gui/control/selectorwidgetbase.py +3 -1
  14. tomwer/gui/edit/nxtomoeditor.py +28 -20
  15. tomwer/gui/edit/test/test_nx_editor.py +58 -1
  16. tomwer/gui/reconstruction/axis/axis.py +16 -13
  17. tomwer/gui/reconstruction/axis/radioaxis.py +0 -1
  18. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +11 -0
  19. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +5 -4
  20. tomwer/gui/stitching/stitching.py +8 -3
  21. tomwer/gui/visualization/dataviewer.py +27 -15
  22. tomwer/gui/visualization/diffviewer/diffviewer.py +9 -8
  23. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +10 -0
  24. tomwer/tests/datasets.py +5 -1
  25. tomwer/utils.py +1 -4
  26. tomwer/version.py +1 -1
  27. {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/METADATA +34 -48
  28. {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/RECORD +34 -34
  29. {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/WHEEL +1 -1
  30. /tomwer-1.3.12-py3.11-nspkg.pth → /tomwer-1.3.26-py3.11-nspkg.pth +0 -0
  31. {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/LICENSE +0 -0
  32. {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/entry_points.txt +0 -0
  33. {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/namespace_packages.txt +0 -0
  34. {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/top_level.txt +0 -0
@@ -63,7 +63,6 @@ class TestSlurmWidget(TestCaseQt):
63
63
  "job_name": "tomwer_{scan}_-_{process}_-_{info}",
64
64
  "n_jobs": 1,
65
65
  "modules": ("tomotools/stable",),
66
- "walltime": "01:00:00",
67
66
  "sbatch_extra_params": {
68
67
  "export": "NONE",
69
68
  "gpu_card": None,
@@ -156,7 +156,9 @@ class _SelectorWidget(qt.QMainWindow):
156
156
 
157
157
  def removeSelectedDatasets(self):
158
158
  sItem = self.dataList.selectedItems()
159
- selection = [_item.text().get_identifier().to_str() for _item in sItem]
159
+ selection = [
160
+ _item.data(qt.Qt.UserRole).get_identifier().to_str() for _item in sItem
161
+ ]
160
162
 
161
163
  with block_signals(self):
162
164
  # make sure sigUpdated is called only once.
@@ -574,28 +574,36 @@ class NXtomoEditor(qt.QWidget):
574
574
  ),
575
575
  solve_empty_dependency=True,
576
576
  )
577
- detector_transformation_path = "/".join(
578
- (
579
- nexus_paths.INSTRUMENT_PATH,
580
- nexus_paths.nx_instrument_paths.DETECTOR_PATH,
581
- nexus_paths.nx_detector_paths.NX_TRANSFORMATIONS,
582
- ),
583
- )
584
- if detector_transformation_path in entry:
585
- del entry[detector_transformation_path]
586
-
587
- detector_transformation_path = "/".join(
588
- (scan.entry, detector_transformation_path)
577
+ if nexus_paths.nx_detector_paths.NX_TRANSFORMATIONS is not None:
578
+ # old NXtomo are not handling NX_TRANSFORMATIONS
579
+ detector_transformation_path = "/".join(
580
+ (
581
+ nexus_paths.INSTRUMENT_PATH,
582
+ nexus_paths.nx_instrument_paths.DETECTOR_PATH,
583
+ nexus_paths.nx_detector_paths.NX_TRANSFORMATIONS,
584
+ ),
585
+ )
586
+ if detector_transformation_path in entry:
587
+ del entry[detector_transformation_path]
588
+
589
+ detector_transformation_path = "/".join(
590
+ (scan.entry, detector_transformation_path)
591
+ )
592
+ else:
593
+ _logger.debug(
594
+ "Old version of NXtomo found. No information about transformation will be saved"
595
+ )
596
+ detector_transformation_path = None
597
+
598
+ if detector_transformation_path is not None:
599
+ dicttonx(
600
+ nx_dict,
601
+ h5file=scan.master_file,
602
+ h5path=detector_transformation_path,
603
+ update_mode="replace",
604
+ mode="a",
589
605
  )
590
606
 
591
- dicttonx(
592
- nx_dict,
593
- h5file=scan.master_file,
594
- h5path=detector_transformation_path,
595
- update_mode="replace",
596
- mode="a",
597
- )
598
-
599
607
  # clear caches to make sure all modifications will be considered
600
608
  scan.clear_caches()
601
609
  scan.clear_frames_caches()
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import h5py
2
3
 
3
4
  import numpy
4
5
  import pytest
@@ -252,7 +253,7 @@ def test_nx_editor_lock(
252
253
  # 3.0 save the nxtomo
253
254
  widget.overwriteNXtomo()
254
255
 
255
- # 4.0 check save went twell
256
+ # 4.0 check save went well
256
257
  overwrite_nx_tomo = NXtomo().load(
257
258
  file_path=file_path,
258
259
  data_path=entry,
@@ -305,3 +306,59 @@ def test_nx_editor_lock(
305
306
  "instrument.detector.x_flipped": (False, False),
306
307
  "instrument.detector.y_flipped": (True, False),
307
308
  }
309
+
310
+
311
+ def test_nxtomo_editor_with_missing_paths(
312
+ tmp_path,
313
+ qtapp, # noqa F811
314
+ ):
315
+ """
316
+ test widget behavior in the case some nxtomo path don't exist
317
+ """
318
+
319
+ # create nx tomo with raw data
320
+ nx_tomo = NXtomo()
321
+ nx_tomo.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
322
+ nx_tomo.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
323
+ nx_tomo.sample.rotation_angle = numpy.linspace(0, 20, num=12)
324
+
325
+ file_path = os.path.join(tmp_path, "nxtomo.nx")
326
+ entry = "entry0000"
327
+ nx_tomo.save(
328
+ file_path=file_path,
329
+ data_path=entry,
330
+ )
331
+ # delete some path that can be missing in some case
332
+ with h5py.File(file_path, mode="a") as h5f:
333
+ assert "entry0000" in h5f
334
+ assert "entry0000/beam" not in h5f
335
+ assert "entry0000/instrument/beam" not in h5f
336
+ assert "entry0000/instrument/detector/distance" not in h5f
337
+ assert "entry0000/instrument/detector/x_pixel_size" not in h5f
338
+ assert "entry0000/instrument/detector/y_pixel_size" not in h5f
339
+ assert "entry0000/instrument/detector/transformations" not in h5f
340
+
341
+ scan = NXtomoScan(file_path, entry)
342
+
343
+ # create the widget and do the edition
344
+ widget = NXtomoEditor()
345
+
346
+ widget.setScan(scan=scan)
347
+
348
+ widget._distanceMetricEntry.setValue(0.05)
349
+ widget._energyEntry.setValue(50)
350
+ widget._xPixelSizeMetricEntry.setValue(0.02)
351
+ widget._yPixelSizeMetricEntry.setValue(0.03)
352
+
353
+ # overwrite the NXtomo
354
+ widget.overwriteNXtomo()
355
+
356
+ # check save went well
357
+ overwrite_nx_tomo = NXtomo().load(
358
+ file_path=file_path,
359
+ data_path=entry,
360
+ )
361
+ assert overwrite_nx_tomo.instrument.detector.x_pixel_size.value == 0.02
362
+ assert overwrite_nx_tomo.instrument.detector.y_pixel_size.value == 0.03
363
+ assert overwrite_nx_tomo.energy.value == 50
364
+ assert overwrite_nx_tomo.instrument.detector.distance.value == 0.05
@@ -31,6 +31,7 @@ __license__ = "MIT"
31
31
  __date__ = "14/10/2019"
32
32
 
33
33
 
34
+ import numpy
34
35
  import logging
35
36
  from typing import Optional
36
37
 
@@ -272,6 +273,7 @@ class _AxisWidget(qt.QMainWindow):
272
273
  self._axis_params.relative_cor_value,
273
274
  self._axis_params.absolute_cor_value,
274
275
  )
276
+ self._controlWidget._positionInfo.setAxis(self._axis_params)
275
277
 
276
278
  # connect signal / slots
277
279
  self._controlWidget.sigComputationRequest.connect(self.sigComputationRequested)
@@ -663,7 +665,13 @@ class _PositionInfoWidget(qt.QWidget):
663
665
  if self._relativePositionQLE.text().startswith((".", "?")):
664
666
  return
665
667
  else:
666
- self.sigRelativeValueSet.emit(float(self._relativePositionQLE.text()))
668
+ value = float(self._relativePositionQLE.text())
669
+ # make sure we only emit the signal if the value changed (and when the Qline has been edited).
670
+ if self._axis.relative_cor_value is None or (
671
+ self._axis is not None
672
+ and not numpy.isclose(value, self._axis.relative_cor_value, atol=1e-3)
673
+ ):
674
+ self.sigRelativeValueSet.emit(value)
667
675
 
668
676
  def _userUpdatedAbsolutePosition(self, *args, **kwargs):
669
677
  palette = self.palette()
@@ -675,24 +683,19 @@ class _PositionInfoWidget(qt.QWidget):
675
683
  if self._absolutePositionQLE.text().startswith((".", "?")):
676
684
  return
677
685
  else:
678
- self.sigAbsolueValueSet.emit(float(self._absolutePositionQLE.text()))
686
+ value = float(self._absolutePositionQLE.text())
687
+ # make sure we only emit the signal if the value changed (and when the Qline has been edited).
688
+ if self._axis.absolute_cor_value is None or (
689
+ self._axis is not None
690
+ and not numpy.isclose(value, self._axis.absolute_cor_value, atol=1e-3)
691
+ ):
692
+ self.sigAbsolueValueSet.emit(value)
679
693
 
680
694
  def setAxis(self, axis):
681
695
  assert isinstance(axis, QAxisRP)
682
696
  if axis == self._axis:
683
697
  return
684
- if self._axis is not None:
685
- self._axis.sigChanged.disconnect(self._updatePosition)
686
698
  self._axis = axis
687
- self._axis.sigChanged.connect(self._updatePosition)
688
- self._updatePosition()
689
-
690
- def _updatePosition(self):
691
- if self._axis:
692
- self.setPosition(
693
- relative_cor=self._axis.relative_cor_value,
694
- abs_cor=self._axis.absolute_cor_value,
695
- )
696
699
 
697
700
  def getPosition(self):
698
701
  return float(self._relativePositionQLE.text())
@@ -1148,7 +1148,6 @@ class _ShiftInformation(qt.QWidget):
1148
1148
  self.setPalette(palette)
1149
1149
 
1150
1150
  def _userEndEditing(self, *args, **kwargs):
1151
- print("user end editing")
1152
1151
  palette = self.palette()
1153
1152
  palette.setColor(
1154
1153
  self.backgroundRole(),
@@ -54,6 +54,7 @@ class DarkRefAndCopyWidget(DarkRefWidget):
54
54
  """Signal emitted when the mode auto change"""
55
55
  sigCopyActivationChanged = qt.Signal()
56
56
  """Signal emitted when the copy is activated or deactivated"""
57
+ sigClearCache = qt.Signal()
57
58
 
58
59
  def __init__(self, save_dir: str, parent=None, reconsparams=None, process_id=None):
59
60
  DarkRefWidget.__init__(
@@ -79,6 +80,7 @@ class DarkRefAndCopyWidget(DarkRefWidget):
79
80
  self._refCopyWidget.sigCopyActivationChanged.connect(
80
81
  self._triggerCopyActivation
81
82
  )
83
+ self._refCopyWidget.sigClearCache.connect(self.sigClearCache)
82
84
 
83
85
  def setRefSetBy(self, scan_id: str):
84
86
  self._refCopyWidget._statusBar.showMessage(f"ref set from {scan_id}")
@@ -155,6 +157,8 @@ class RefCopyWidget(qt.QGroupBox):
155
157
  """Signal emitted when the mode auto change"""
156
158
  sigCopyActivationChanged = qt.Signal()
157
159
  """Signal emitted when the copy is activated or deactivated"""
160
+ sigClearCache = qt.Signal()
161
+ """Signal when the cache needs to be cleared"""
158
162
 
159
163
  _DEFAULT_DIRECTORY = "/lbsram/data/visitor"
160
164
  """Default directory used when the user need to set path to references"""
@@ -190,6 +194,12 @@ class RefCopyWidget(qt.QGroupBox):
190
194
  spacer = qt.QWidget(self)
191
195
  spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
192
196
  self.layout().addWidget(spacer)
197
+ self._removeCacheFile = qt.QPushButton("clear cache")
198
+ self._removeCacheFile.setToolTip(
199
+ "Remove the file used for cacheing reduce dark / flat."
200
+ )
201
+ self.layout().addWidget(self._removeCacheFile)
202
+
193
203
  self.layout().addWidget(self.__createStatusBarGUI())
194
204
 
195
205
  self.setModeAuto(True)
@@ -201,6 +211,7 @@ class RefCopyWidget(qt.QGroupBox):
201
211
  # connect signal / slot
202
212
  self.toggled.connect(self._triggerCopyActivated)
203
213
  self._qcbAutoMode.toggled.connect(self._triggerModeAutoChanged)
214
+ self._removeCacheFile.released.connect(self.sigClearCache)
204
215
 
205
216
  def _triggerCopyActivated(self, *args, **kwargs):
206
217
  self.sigCopyActivationChanged.emit()
@@ -188,13 +188,14 @@ class _NabuPreProcessingConfig(_NabuStageConfigBase, qt.QWidget):
188
188
 
189
189
  # option dedicated to Helical
190
190
  ## process file
191
- self._processFileQLE = qt.QLabel("file containing weights maps", self)
191
+ self._processFileLabel = qt.QLabel("file containing weights maps", self)
192
+ self.registerWidget(self._processFileLabel, "advanced")
193
+ self.layout().addWidget(self._processFileLabel, 20, 0, 1, 1)
194
+ self._processFileQLE = qt.QLineEdit("", self)
195
+ self.registerWidget(self._processFileQLE, "advanced")
192
196
  self._processFileQLE.setToolTip(
193
197
  "also know as 'process_file'. If you don't have this file it can be created from the 'helical-prepare-weights' widget"
194
198
  )
195
- self.layout().addWidget(self._processFileQLE, 20, 0, 1, 1)
196
- self._processFileQLE = qt.QLineEdit("", self)
197
- self.registerWidget(self._processFileQLE, "advanced")
198
199
  self.layout().addWidget(self._processFileQLE, 20, 1, 1, 3)
199
200
 
200
201
  # style
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import os
3
+ import shutil
3
4
  import tempfile
4
5
  import functools
5
6
 
@@ -399,7 +400,7 @@ class ZStitchingWindow(qt.QMainWindow):
399
400
  # separator
400
401
  toolbar.addSeparator()
401
402
 
402
- # configuraiton level / mode
403
+ # configuration level / mode
403
404
  self.__configurationModesAction = qt.QAction(self)
404
405
  self.__configurationModesAction.setCheckable(False)
405
406
  menu = qt.QMenu(self)
@@ -602,6 +603,8 @@ class ZStitchingWindow(qt.QMainWindow):
602
603
  self._callbackToSetSlurmConfig = callback
603
604
 
604
605
  def close(self):
606
+ # remove folder used for preview
607
+ shutil.rmtree(self._previewFolder, ignore_errors=True)
605
608
  self._widget.close()
606
609
  # requested for the waiting plot update
607
610
  super().close()
@@ -618,7 +621,6 @@ class ZStitchingWindow(qt.QMainWindow):
618
621
 
619
622
  def getPreviewFolder(self):
620
623
  if self._previewFolder is None:
621
- # TODO: improve management of file: must be removed when the widget is closed...
622
624
  self._previewFolder = tempfile.mkdtemp(prefix="tomwer_stitcher_preview")
623
625
  return self._previewFolder
624
626
 
@@ -782,7 +784,6 @@ class ZStitchingWindow(qt.QMainWindow):
782
784
  tomo_obj = existing_tomo_obj.get(tomo_obj_id, None)
783
785
  if tomo_obj is None:
784
786
  continue
785
- # TODO: recuperer le tomo obj a partir de l'identifiant
786
787
  if update_requested[0]:
787
788
  tomo_obj.stitching_metadata.setPxPos(int(new_axis_0_pos), 0)
788
789
  if update_requested[2]:
@@ -859,6 +860,10 @@ class ZStitchingWindow(qt.QMainWindow):
859
860
  level >= ConfigurationLevel.ADVANCED
860
861
  )
861
862
 
863
+ def close(self):
864
+ shutil.rmtree(self._previewFolder, ignore_errors=True)
865
+ super().close()
866
+
862
867
 
863
868
  def concatenate_dict(dict_1, dict_2) -> dict:
864
869
  """update dict which has dict as values. And we want concatenate those values to"""
@@ -34,7 +34,6 @@ from silx.gui import qt
34
34
  from silx.gui.dialog.ColormapDialog import DisplayMode
35
35
  from silx.gui.plot.ImageStack import ImageStack as _ImageStack
36
36
  from silx.gui.plot.ImageStack import UrlLoader
37
- from silx.gui.utils.signal import SignalProxy
38
37
  from silx.io.url import DataUrl
39
38
  from silx.utils.enum import Enum as _Enum
40
39
 
@@ -86,17 +85,6 @@ class DataViewer(qt.QMainWindow):
86
85
  self._viewer.getPlotWidget().setKeepDataAspectRatio(True)
87
86
  self.setCentralWidget(self._viewer)
88
87
 
89
- # signal / slot
90
- # add a signal proxy on the QSlider
91
- self._viewer._slider.sigCurrentUrlIndexChanged.disconnect(
92
- self._viewer.setCurrentUrlIndex
93
- )
94
- self._proxySig = SignalProxy(
95
- self._viewer._slider.sigCurrentUrlIndexChanged,
96
- delay=0.3,
97
- slot=self._urlIndexDelayed,
98
- )
99
-
100
88
  # display control
101
89
  self._controls = DisplayControl(parent=self)
102
90
  self._controlsDW = qt.QDockWidget(self)
@@ -110,6 +98,33 @@ class DataViewer(qt.QMainWindow):
110
98
  self._controls.sigDisplayModeChanged.connect(self._updateDisplay)
111
99
  self._controls.sigDisplayModeChanged.connect(self.sigConfigChanged)
112
100
 
101
+ # upgrade of the slider (see details in '__sliderPressed' docstring).
102
+ horizontal_slider = self._viewer._slider
103
+ horizontal_slider._slider.sliderReleased.connect(self.__sliderReleased)
104
+ horizontal_slider._slider.sliderPressed.connect(self.__sliderPressed)
105
+
106
+ def __sliderPressed(self):
107
+ """
108
+ today each time the slider value is modified it will load the frame and display it
109
+ but in our case we cannot afford it as it will take too much memory.
110
+ So we will disconnect the callback (self._viewer.setCurrentUrlIndex) until the slider is active
111
+ and reactivate it afterwards
112
+ """
113
+ self._viewer._slider.sigCurrentUrlIndexChanged.disconnect(
114
+ self._viewer.setCurrentUrlIndex
115
+ )
116
+
117
+ def __sliderReleased(self):
118
+ """
119
+ See details in '__sliderPressed'
120
+ """
121
+ horizontal_slider = self._viewer._slider
122
+ self._viewer._slider.sigCurrentUrlIndexChanged.connect(
123
+ self._viewer.setCurrentUrlIndex
124
+ )
125
+ # set the url with the latest value to display the requested frame
126
+ self._viewer.setCurrentUrlIndex(horizontal_slider.value())
127
+
113
128
  def getPlotWidget(self):
114
129
  return self._viewer.getPlotWidget()
115
130
 
@@ -134,9 +149,6 @@ class DataViewer(qt.QMainWindow):
134
149
  self._viewer = None
135
150
  super().close()
136
151
 
137
- def _urlIndexDelayed(self, *args, **kwargs):
138
- self._viewer.setCurrentUrlIndex(args[0][0])
139
-
140
152
  def getScan(self):
141
153
  if self._scan:
142
154
  return self._scan()
@@ -25,6 +25,7 @@
25
25
  """
26
26
  contains gui relative frame difference display
27
27
  """
28
+ from __future__ import annotations
28
29
 
29
30
  __authors__ = ["H. Payno"]
30
31
  __license__ = "MIT"
@@ -148,7 +149,7 @@ class _FrameSelector(qt.QWidget):
148
149
  return
149
150
 
150
151
  urls = []
151
- angles = []
152
+ urls_to_angles: dict[str, float] = {}
152
153
  self._currentFrameUrlsText.clear()
153
154
  self._frameUrlCB.clear()
154
155
  if type_selected == self.FrameType.DARKS:
@@ -162,7 +163,7 @@ class _FrameSelector(qt.QWidget):
162
163
  angles_and_urls = self._scan.get_proj_angle_url(with_alignment=False)
163
164
  for angle, url in angles_and_urls.items():
164
165
  urls.append(url)
165
- angles.append(angle)
166
+ urls_to_angles[url.path()] = angle
166
167
  else:
167
168
  urls = self._scan.projections.values()
168
169
  elif type_selected == self.FrameType.ALIGN_PROJ:
@@ -174,14 +175,14 @@ class _FrameSelector(qt.QWidget):
174
175
  raise ValueError(f"Type {type_selected} not managed")
175
176
  urls = sorted(urls, key=lambda url: url.path())
176
177
 
177
- # if thre is some angles missing, avoiding setting any angle because they are probably wrong
178
+ # if there is some angles missing, avoiding setting any angle because they are probably wrong
178
179
  # this will probably fail with EDF but this is legacy
179
- if len(angles) != len(urls):
180
- angles = []
180
+ if len(urls_to_angles) != len(urls):
181
+ urls_to_angles.clear()
181
182
 
182
- for i_url, url in enumerate(urls):
183
- if len(angles) > 0:
184
- text = f"angle={angles[i_url]}&"
183
+ for url in urls:
184
+ if len(urls_to_angles) > 0:
185
+ text = f"angle={urls_to_angles[url.path()]}&"
185
186
  else:
186
187
  text = ""
187
188
  if url.data_slice() is not None:
@@ -30,6 +30,7 @@ import functools
30
30
  import logging
31
31
  import shutil
32
32
  import tempfile
33
+ import os
33
34
 
34
35
  from processview.core.manager import DatasetState, ProcessManager
35
36
  from processview.core.superviseprocess import SuperviseProcess
@@ -132,6 +133,15 @@ class DarkRefCopyProcessStack(FIFO, qt.QObject):
132
133
  def _create_processing_thread(self, process_id=None) -> qt.QThread:
133
134
  return _ProcessingThread(process_id=process_id, save_dir=self._save_dir)
134
135
 
136
+ def clear_cache(self):
137
+ """
138
+ remove the file used to cache the reduced darks / flats.
139
+ This can be used in the case it contain unrelevant data. Like frame with another shape...
140
+ """
141
+ cache_file = DarkRefsCopy.get_save_file(self._save_dir)
142
+ if os.path.exists(cache_file):
143
+ os.remove(cache_file)
144
+
135
145
 
136
146
  class _ProcessingThread(ProcessingThread, SuperviseProcess):
137
147
  """
tomwer/tests/datasets.py CHANGED
@@ -1,5 +1,9 @@
1
1
  import os
2
- from tomoscan.test.datasets import GitlabProject
2
+
3
+ try:
4
+ from tomoscan.test.datasets import GitlabProject
5
+ except ImportError:
6
+ from tomoscan.tests.datasets import GitlabProject
3
7
 
4
8
  TomwerCIDatasets = GitlabProject(
5
9
  branch_name="tomwer",
tomwer/utils.py CHANGED
@@ -81,10 +81,7 @@ class LauncherCommand(_LauncherCommand):
81
81
  """Description of a command"""
82
82
 
83
83
  def get_module(self):
84
- """Returns the python module to execute. If any.
85
-
86
- :rtype: module
87
- """
84
+ """Returns the python module to execute. If any."""
88
85
  try:
89
86
  module = importlib.import_module(self.module_name)
90
87
  return module
tomwer/version.py CHANGED
@@ -77,7 +77,7 @@ RELEASE_LEVEL_VALUE = {
77
77
 
78
78
  MAJOR = 1
79
79
  MINOR = 3
80
- MICRO = 12
80
+ MICRO = 26
81
81
  RELEV = "final" # <16
82
82
  SERIAL = 0 # <16
83
83