nabu 2024.2.4__py3-none-any.whl → 2025.1.0.dev4__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 (164) hide show
  1. doc/doc_config.py +32 -0
  2. nabu/__init__.py +1 -1
  3. nabu/app/bootstrap_stitching.py +4 -2
  4. nabu/app/cast_volume.py +7 -13
  5. nabu/app/cli_configs.py +0 -5
  6. nabu/app/compare_volumes.py +1 -1
  7. nabu/app/composite_cor.py +2 -4
  8. nabu/app/correct_rot.py +0 -8
  9. nabu/app/diag_to_pix.py +5 -6
  10. nabu/app/diag_to_rot.py +10 -11
  11. nabu/app/multicor.py +1 -1
  12. nabu/app/parse_reconstruction_log.py +1 -0
  13. nabu/app/prepare_weights_double.py +1 -2
  14. nabu/app/reconstruct_helical.py +1 -5
  15. nabu/app/reduce_dark_flat.py +0 -2
  16. nabu/app/rotate.py +3 -1
  17. nabu/app/tests/test_reduce_dark_flat.py +2 -2
  18. nabu/app/validator.py +1 -4
  19. nabu/cuda/convolution.py +1 -1
  20. nabu/cuda/fft.py +1 -1
  21. nabu/cuda/medfilt.py +1 -1
  22. nabu/cuda/padding.py +1 -1
  23. nabu/cuda/src/cone.cu +19 -9
  24. nabu/cuda/src/hierarchical_backproj.cu +16 -0
  25. nabu/cuda/utils.py +2 -2
  26. nabu/estimation/alignment.py +17 -31
  27. nabu/estimation/cor.py +23 -29
  28. nabu/estimation/cor_sino.py +2 -8
  29. nabu/estimation/focus.py +4 -8
  30. nabu/estimation/tests/test_alignment.py +2 -0
  31. nabu/estimation/tests/test_tilt.py +1 -1
  32. nabu/estimation/tilt.py +5 -4
  33. nabu/io/cast_volume.py +5 -5
  34. nabu/io/detector_distortion.py +5 -6
  35. nabu/io/reader.py +3 -3
  36. nabu/io/reader_helical.py +5 -4
  37. nabu/io/tests/test_cast_volume.py +2 -2
  38. nabu/io/tests/test_readers.py +4 -4
  39. nabu/io/tests/test_writers.py +2 -2
  40. nabu/io/utils.py +8 -4
  41. nabu/io/writer.py +1 -2
  42. nabu/misc/fftshift.py +1 -1
  43. nabu/misc/fourier_filters.py +1 -1
  44. nabu/misc/histogram.py +1 -1
  45. nabu/misc/histogram_cuda.py +1 -1
  46. nabu/misc/padding_base.py +1 -1
  47. nabu/misc/rotation.py +1 -1
  48. nabu/misc/rotation_cuda.py +1 -1
  49. nabu/misc/tests/test_binning.py +1 -1
  50. nabu/misc/transpose.py +1 -1
  51. nabu/misc/unsharp.py +1 -1
  52. nabu/misc/unsharp_cuda.py +1 -1
  53. nabu/misc/unsharp_opencl.py +1 -1
  54. nabu/misc/utils.py +1 -1
  55. nabu/opencl/fft.py +1 -1
  56. nabu/opencl/padding.py +1 -1
  57. nabu/opencl/utils.py +8 -8
  58. nabu/pipeline/config.py +2 -2
  59. nabu/pipeline/config_validators.py +4 -3
  60. nabu/pipeline/datadump.py +3 -3
  61. nabu/pipeline/estimators.py +6 -6
  62. nabu/pipeline/fullfield/chunked.py +4 -5
  63. nabu/pipeline/fullfield/dataset_validator.py +0 -1
  64. nabu/pipeline/fullfield/nabu_config.py +2 -1
  65. nabu/pipeline/fullfield/reconstruction.py +9 -8
  66. nabu/pipeline/helical/dataset_validator.py +3 -4
  67. nabu/pipeline/helical/fbp.py +4 -4
  68. nabu/pipeline/helical/filtering.py +5 -4
  69. nabu/pipeline/helical/gridded_accumulator.py +9 -10
  70. nabu/pipeline/helical/helical_chunked_regridded.py +1 -0
  71. nabu/pipeline/helical/helical_reconstruction.py +10 -7
  72. nabu/pipeline/helical/helical_utils.py +1 -2
  73. nabu/pipeline/helical/nabu_config.py +1 -0
  74. nabu/pipeline/helical/span_strategy.py +1 -0
  75. nabu/pipeline/helical/weight_balancer.py +1 -2
  76. nabu/pipeline/tests/__init__.py +0 -0
  77. nabu/pipeline/utils.py +1 -1
  78. nabu/pipeline/writer.py +1 -1
  79. nabu/preproc/alignment.py +0 -10
  80. nabu/preproc/ctf.py +8 -8
  81. nabu/preproc/ctf_cuda.py +1 -1
  82. nabu/preproc/double_flatfield_cuda.py +2 -2
  83. nabu/preproc/double_flatfield_variable_region.py +0 -1
  84. nabu/preproc/flatfield.py +1 -1
  85. nabu/preproc/flatfield_cuda.py +1 -2
  86. nabu/preproc/flatfield_variable_region.py +3 -3
  87. nabu/preproc/phase.py +2 -4
  88. nabu/preproc/phase_cuda.py +2 -2
  89. nabu/preproc/shift_cuda.py +0 -1
  90. nabu/preproc/tests/test_ctf.py +3 -3
  91. nabu/preproc/tests/test_double_flatfield.py +1 -1
  92. nabu/preproc/tests/test_flatfield.py +1 -1
  93. nabu/preproc/tests/test_vshift.py +4 -1
  94. nabu/processing/azim.py +2 -2
  95. nabu/processing/convolution_cuda.py +6 -4
  96. nabu/processing/fft_base.py +1 -1
  97. nabu/processing/fft_cuda.py +19 -8
  98. nabu/processing/fft_opencl.py +9 -4
  99. nabu/processing/fftshift.py +1 -1
  100. nabu/processing/histogram.py +1 -1
  101. nabu/processing/muladd.py +0 -1
  102. nabu/processing/padding_base.py +1 -1
  103. nabu/processing/padding_cuda.py +0 -1
  104. nabu/processing/processing_base.py +1 -1
  105. nabu/processing/tests/test_fft.py +1 -1
  106. nabu/processing/tests/test_fftshift.py +1 -1
  107. nabu/processing/tests/test_medfilt.py +1 -3
  108. nabu/processing/tests/test_padding.py +1 -1
  109. nabu/processing/tests/test_roll.py +1 -1
  110. nabu/processing/unsharp_opencl.py +1 -1
  111. nabu/reconstruction/astra.py +245 -0
  112. nabu/reconstruction/cone.py +9 -4
  113. nabu/reconstruction/fbp_base.py +2 -2
  114. nabu/reconstruction/filtering_cuda.py +1 -1
  115. nabu/reconstruction/hbp.py +16 -3
  116. nabu/reconstruction/mlem.py +0 -1
  117. nabu/reconstruction/projection.py +3 -5
  118. nabu/reconstruction/sinogram.py +1 -1
  119. nabu/reconstruction/sinogram_cuda.py +0 -1
  120. nabu/reconstruction/tests/test_cone.py +76 -3
  121. nabu/reconstruction/tests/test_deringer.py +2 -2
  122. nabu/reconstruction/tests/test_fbp.py +1 -1
  123. nabu/reconstruction/tests/test_halftomo.py +27 -1
  124. nabu/reconstruction/tests/test_mlem.py +3 -2
  125. nabu/reconstruction/tests/test_projector.py +7 -2
  126. nabu/reconstruction/tests/test_sino_normalization.py +0 -1
  127. nabu/resources/dataset_analyzer.py +4 -4
  128. nabu/resources/gpu.py +4 -4
  129. nabu/resources/logger.py +4 -4
  130. nabu/resources/nxflatfield.py +2 -2
  131. nabu/resources/tests/test_nxflatfield.py +4 -4
  132. nabu/stitching/alignment.py +1 -4
  133. nabu/stitching/config.py +19 -16
  134. nabu/stitching/frame_composition.py +8 -10
  135. nabu/stitching/overlap.py +2 -2
  136. nabu/stitching/slurm_utils.py +2 -2
  137. nabu/stitching/stitcher/base.py +2 -0
  138. nabu/stitching/stitcher/dumper/base.py +0 -1
  139. nabu/stitching/stitcher/dumper/postprocessing.py +1 -1
  140. nabu/stitching/stitcher/post_processing.py +6 -6
  141. nabu/stitching/stitcher/pre_processing.py +13 -11
  142. nabu/stitching/stitcher/single_axis.py +3 -4
  143. nabu/stitching/stitcher_2D.py +2 -1
  144. nabu/stitching/tests/test_config.py +7 -8
  145. nabu/stitching/tests/test_sample_normalization.py +1 -1
  146. nabu/stitching/tests/test_slurm_utils.py +1 -2
  147. nabu/stitching/tests/test_z_postprocessing_stitching.py +1 -1
  148. nabu/stitching/tests/test_z_preprocessing_stitching.py +4 -4
  149. nabu/stitching/utils/tests/__init__.py +0 -0
  150. nabu/stitching/utils/tests/test_post-processing.py +1 -0
  151. nabu/stitching/utils/utils.py +10 -12
  152. nabu/tests.py +0 -3
  153. nabu/testutils.py +30 -8
  154. nabu/utils.py +28 -18
  155. {nabu-2024.2.4.dist-info → nabu-2025.1.0.dev4.dist-info}/METADATA +25 -25
  156. nabu-2025.1.0.dev4.dist-info/RECORD +320 -0
  157. {nabu-2024.2.4.dist-info → nabu-2025.1.0.dev4.dist-info}/WHEEL +1 -1
  158. nabu/io/tests/test_detector_distortion.py +0 -178
  159. nabu/resources/tests/test_extract.py +0 -9
  160. nabu-2024.2.4.dist-info/RECORD +0 -318
  161. /nabu/{stitching → app}/tests/__init__.py +0 -0
  162. {nabu-2024.2.4.dist-info → nabu-2025.1.0.dev4.dist-info}/LICENSE +0 -0
  163. {nabu-2024.2.4.dist-info → nabu-2025.1.0.dev4.dist-info}/entry_points.txt +0 -0
  164. {nabu-2024.2.4.dist-info → nabu-2025.1.0.dev4.dist-info}/top_level.txt +0 -0
nabu/resources/gpu.py CHANGED
@@ -131,7 +131,7 @@ def pick_gpus_auto(cuda_gpus, opencl_platforms, n_gpus):
131
131
  return (gpu1["device_id"] == gpu2["device_id"]) and (gpu1["name"] == gpu2["name"])
132
132
 
133
133
  def is_in_gpus(avail_gpus, query_gpu):
134
- for gpu in avail_gpus:
134
+ for gpu in avail_gpus: # noqa: SIM110
135
135
  if gpu_equal(gpu, query_gpu):
136
136
  return True
137
137
  return False
@@ -142,8 +142,8 @@ def pick_gpus_auto(cuda_gpus, opencl_platforms, n_gpus):
142
142
  chosen_gpus = list(cuda_gpus.values())
143
143
  if len(chosen_gpus) >= n_gpus:
144
144
  return chosen_gpus
145
- for platform, gpus in opencl_platforms.items():
146
- for gpu_id, gpu in gpus.items():
145
+ for platform, gpus in opencl_platforms.items(): # noqa: PERF102
146
+ for gpu_id, gpu in gpus.items(): # noqa: PERF102
147
147
  if not (is_in_gpus(chosen_gpus, gpu)):
148
148
  # TODO prioritize some OpenCL implementations ?
149
149
  chosen_gpus.append(gpu)
@@ -166,5 +166,5 @@ def pick_gpus_nvidia(cuda_gpus, n_gpus):
166
166
  gpus_cc_sorted = sorted(gpus_cc, key=lambda x: x[1], reverse=True)
167
167
  res = []
168
168
  for i in range(n_gpus):
169
- res.append(cuda_gpus[gpus_cc_sorted[i][0]])
169
+ res.append(cuda_gpus[gpus_cc_sorted[i][0]]) # noqa: PERF401
170
170
  return res
nabu/resources/logger.py CHANGED
@@ -2,7 +2,7 @@ import logging
2
2
  import logging.config
3
3
 
4
4
 
5
- class Logger(object):
5
+ class Logger:
6
6
  def __init__(self, loggername, level="DEBUG", logfile="logger.log", console=True):
7
7
  """
8
8
  Configure a Logger object.
@@ -30,7 +30,7 @@ class Logger(object):
30
30
 
31
31
  def _configure_logger(self):
32
32
  conf = self._get_default_config_dict()
33
- for handler in conf["handlers"].keys():
33
+ for handler in conf["handlers"]:
34
34
  conf["handlers"][handler]["level"] = self.level.upper()
35
35
  conf["loggers"][self.loggername]["level"] = self.level.upper()
36
36
  if not (self.console):
@@ -103,7 +103,7 @@ def LoggerOrPrint(logger):
103
103
  return logger
104
104
 
105
105
 
106
- class PrinterLogger(object):
106
+ class PrinterLogger:
107
107
  def __init__(self):
108
108
  methods = [
109
109
  "debug",
@@ -122,7 +122,7 @@ LogLevel = {
122
122
  "notset": logging.NOTSET,
123
123
  "debug": logging.DEBUG,
124
124
  "info": logging.INFO,
125
- "warn": logging.WARN,
125
+ "warn": logging.WARNING,
126
126
  "warning": logging.WARNING,
127
127
  "error": logging.ERROR,
128
128
  "critical": logging.CRITICAL,
@@ -202,7 +202,7 @@ def update_dataset_info_flats_darks(dataset_info, flatfield_mode, output_dir=Non
202
202
  elif _can_load_from("output"):
203
203
  where_to_load_from = "output"
204
204
 
205
- if where_to_load_from == None and flatfield_mode == "force-load":
205
+ if where_to_load_from is None and flatfield_mode == "force-load":
206
206
  raise ValueError("Could not load darks/flats (using 'force-load')")
207
207
 
208
208
  if where_to_load_from is not None:
@@ -218,7 +218,7 @@ def update_dataset_info_flats_darks(dataset_info, flatfield_mode, output_dir=Non
218
218
  setattr(
219
219
  dataset_info,
220
220
  frame_type,
221
- {k: get_data(red_frames_dict[k]) for k in red_frames_dict.keys()},
221
+ {k: get_data(red_frames_dict[k]) for k in red_frames_dict},
222
222
  )
223
223
  if frame_type == "flats":
224
224
  dataset_info.flats_srcurrent = red_frames_info.machine_electric_current
@@ -83,8 +83,8 @@ class TestNXFlatField:
83
83
  update_dataset_info_flats_darks(dataset_info, True, output_dir=output_dir)
84
84
  # After reduction (median/mean), the flats/darks are located in another file.
85
85
  # median(series_1) goes to entry/flats/idx1, mean(series_2) goes to entry/flats/idx2, etc.
86
- assert set(dataset_info.flats.keys()) == set(s.start for s in self.params["flats_pos"])
87
- assert set(dataset_info.darks.keys()) == set(s.start for s in self.params["darks_pos"])
86
+ assert set(dataset_info.flats.keys()) == set(s.start for s in self.params["flats_pos"]) # noqa: C401
87
+ assert set(dataset_info.darks.keys()) == set(s.start for s in self.params["darks_pos"]) # noqa: C401
88
88
 
89
89
  # Check that the computations were correct
90
90
  # Loads the entire volume in memory ! So keep the data volume small for the tests
@@ -97,8 +97,8 @@ class TestNXFlatField:
97
97
  expected_darks[s.start] = self._reduction_func["darks"](data_volume[s.start : s.stop], axis=0)
98
98
 
99
99
  flats = dataset_info.flats
100
- for idx in flats.keys():
100
+ for idx in flats:
101
101
  assert np.allclose(flats[idx], expected_flats[idx])
102
102
  darks = dataset_info.darks
103
- for idx in darks.keys():
103
+ for idx in darks:
104
104
  assert np.allclose(darks[idx], expected_darks[idx])
@@ -2,9 +2,6 @@ import h5py
2
2
  import numpy
3
3
  from typing import Union
4
4
  from silx.utils.enum import Enum as _Enum
5
- from tomoscan.volumebase import VolumeBase
6
- from tomoscan.esrf.volume.hdf5volume import HDF5Volume
7
- from nabu.io.utils import DatasetReader
8
5
 
9
6
 
10
7
  class AlignmentAxis2(_Enum):
@@ -151,7 +148,7 @@ class PaddedRawData:
151
148
  @property
152
149
  def shape(self):
153
150
  if self._shape is None:
154
- self._shape = tuple(
151
+ self._shape = tuple( # noqa: C409
155
152
  (
156
153
  self._raw_data_shape[0],
157
154
  numpy.sum(
nabu/stitching/config.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from math import ceil
2
- from typing import Any, Iterable, Optional, Union, Sized
2
+ from typing import Optional, Union
3
+ from collections.abc import Iterable, Sized
3
4
  from dataclasses import dataclass
4
5
  import numpy
5
6
  from pyunitsystem.metricsystem import MetricSystem
@@ -12,13 +13,12 @@ from ..pipeline.config_validators import (
12
13
  convert_to_bool,
13
14
  )
14
15
  from ..utils import concatenate_dict, convert_str_to_tuple
15
- from ..io.utils import get_output_volume
16
16
  from .overlap import OverlapStitchingStrategy
17
17
  from .utils.utils import ShiftAlgorithm
18
18
  from .definitions import StitchingType
19
19
  from .alignment import AlignmentAxis1, AlignmentAxis2
20
- from pyunitsystem.metricsystem import MetricSystem
21
20
 
21
+ # ruff: noqa: S105
22
22
 
23
23
  KEY_IMG_REG_METHOD = "img_reg_method"
24
24
 
@@ -205,7 +205,7 @@ def _str_to_dict(my_str: Union[str, dict]):
205
205
 
206
206
 
207
207
  def _dict_to_str(ddict: dict):
208
- return ";".join([f"{str(key)}={str(value)}" for key, value in ddict.items()])
208
+ return ";".join([f"{key!s}={value!s}" for key, value in ddict.items()])
209
209
 
210
210
 
211
211
  def str_to_shifts(my_str: Optional[str]) -> Union[str, tuple]:
@@ -235,8 +235,8 @@ def _valid_stitching_kernels_params(my_dict: Union[dict, str]):
235
235
  my_dict = _str_to_dict(my_str=my_dict)
236
236
 
237
237
  valid_keys = (KEY_THRESHOLD_FREQUENCY, KEY_SIDE)
238
- for key in my_dict.keys():
239
- if not key in valid_keys:
238
+ for key in my_dict:
239
+ if key not in valid_keys:
240
240
  raise KeyError(f"{key} is a unrecognized key")
241
241
  return my_dict
242
242
 
@@ -253,8 +253,8 @@ def _valid_shifts_params(my_dict: Union[dict, str]):
253
253
  KEY_LOW_PASS_FILTER,
254
254
  KEY_SIDE,
255
255
  )
256
- for key in my_dict.keys():
257
- if not key in valid_keys:
256
+ for key in my_dict:
257
+ if key not in valid_keys:
258
258
  raise KeyError(f"{key} is a unrecognized key")
259
259
  return my_dict
260
260
 
@@ -401,16 +401,17 @@ class NormalizationBySample:
401
401
  NORMALIZATION_BY_SAMPLE_WIDTH: self.width,
402
402
  }
403
403
 
404
- def __eq__(self, __value: object) -> bool:
405
- if not isinstance(__value, NormalizationBySample):
404
+ def __eq__(self, value: object, /) -> bool:
405
+ if not isinstance(value, NormalizationBySample):
406
406
  return False
407
407
  else:
408
- return self.to_dict() == __value.to_dict()
408
+ return self.to_dict() == value.to_dict()
409
409
 
410
410
 
411
411
  @dataclass
412
412
  class SlurmConfig:
413
- "configuration for slurm jobs"
413
+ """configuration for slurm jobs"""
414
+
414
415
  partition: str = "" # note: must stay empty to make by default we don't use slurm (use by the configuration file)
415
416
  mem: str = "128"
416
417
  n_jobs: int = 1
@@ -429,7 +430,7 @@ class SlurmConfig:
429
430
  )
430
431
 
431
432
  def to_dict(self) -> dict:
432
- "dump configuration to dict"
433
+ """dump configuration to dict"""
433
434
  return {
434
435
  SLURM_PARTITION: self.partition if self.partition is not None else "",
435
436
  SLURM_MEM: self.mem,
@@ -459,15 +460,17 @@ class SlurmConfig:
459
460
  )
460
461
 
461
462
 
462
- def _cast_shift_to_str(shifts: Union[tuple, str, None]) -> str:
463
+ def _cast_shift_to_str(shifts: Union[tuple, numpy.ndarray, str, None]) -> str:
463
464
  if shifts is None:
464
465
  return ""
465
466
  elif isinstance(shifts, ShiftAlgorithm):
466
467
  return shifts.value
467
468
  elif isinstance(shifts, str):
468
469
  return shifts
469
- elif isinstance(shifts, (tuple, list)):
470
+ elif isinstance(shifts, (tuple, list, numpy.ndarray)):
470
471
  return ";".join([str(value) for value in shifts])
472
+ else:
473
+ raise TypeError(f"unexpected type: {type(shifts)}")
471
474
 
472
475
 
473
476
  @dataclass
@@ -771,7 +774,7 @@ class SingleAxisConfigMetaClass(type):
771
774
  warning: this class is used by tomwer as well
772
775
  """
773
776
 
774
- def __new__(mcls, name, bases, attrs, axis=None):
777
+ def __new__(mcls, name, bases, attrs, axis=None): # noqa: N804
775
778
  # assert axis is not None
776
779
  mcls = super().__new__(mcls, name, bases, attrs)
777
780
  mcls._axis = axis
@@ -31,7 +31,7 @@ class FrameComposition:
31
31
  )
32
32
 
33
33
  def compose(self, output_frame: numpy.ndarray, input_frames: tuple):
34
- if not output_frame.ndim in (2, 3):
34
+ if output_frame.ndim not in (2, 3):
35
35
  raise TypeError(
36
36
  f"output_frame is expected to be 2D (gray scale) or 3D (RGB(A)) and not {output_frame.ndim}"
37
37
  )
@@ -74,9 +74,10 @@ class FrameComposition:
74
74
  local_start_indices.extend(
75
75
  [ceil(key_line[1] + kernel.overlap_size / 2) for (key_line, kernel) in zip(key_lines, overlap_kernels)]
76
76
  )
77
- local_end_indices = list(
78
- [ceil(key_line[0] - kernel.overlap_size / 2) for (key_line, kernel) in zip(key_lines, overlap_kernels)]
79
- )
77
+ local_end_indices = [
78
+ ceil(key_line[0] - kernel.overlap_size / 2) for (key_line, kernel) in zip(key_lines, overlap_kernels)
79
+ ]
80
+
80
81
  local_end_indices.append(frames[-1].shape[stitching_axis])
81
82
 
82
83
  for (
@@ -155,9 +156,6 @@ class FrameComposition:
155
156
  print(
156
157
  f"stitch_frame[{stitch_global_start}:{stitch_global_end}] = stitched_frame_{i_frame}[{stitch_local_start}:{stitch_local_end}]"
157
158
  )
158
- else:
159
- i_frame += 1
160
- raw_local_start, raw_local_end, raw_global_start, raw_global_end = list(raw_composition.browse())[-1]
161
- print(
162
- f"stitch_frame[{raw_global_start}:{raw_global_end}] = frame_{i_frame}[{raw_local_start}:{raw_local_end}]"
163
- )
159
+ i_frame += 1
160
+ raw_local_start, raw_local_end, raw_global_start, raw_global_end = list(raw_composition.browse())[-1]
161
+ print(f"stitch_frame[{raw_global_start}:{raw_global_end}] = frame_{i_frame}[{raw_local_start}:{raw_local_end}]")
nabu/stitching/overlap.py CHANGED
@@ -64,7 +64,7 @@ class ImageStichOverlapKernel(OverlapKernelBase):
64
64
  f"frame_width is expected to be a positive int, {frame_unstitched_axis_size} - not {frame_unstitched_axis_size} ({type(frame_unstitched_axis_size)})"
65
65
  )
66
66
 
67
- if not stitching_axis in (0, 1):
67
+ if stitching_axis not in (0, 1):
68
68
  raise ValueError(
69
69
  "stitching_axis is expected to be the axis along which stitching must be done. It should be '0' or '1'"
70
70
  )
@@ -391,7 +391,7 @@ def check_overlaps(frames: Union[tuple, numpy.ndarray], positions: tuple, axis:
391
391
 
392
392
  :return: (tested_bounding_box, bounding_boxes_to_test)
393
393
  """
394
- my_bounding_boxes = {bb_index: bb for bb_index, bb in enumerate(my_bounding_boxes)}
394
+ my_bounding_boxes = {bb_index: bb for bb_index, bb in enumerate(my_bounding_boxes)} # noqa: C416
395
395
  bounding_boxes = dict(
396
396
  filter(
397
397
  lambda pair: pair[0] not in (index - 1, index, index + 1),
@@ -177,7 +177,7 @@ def split_slices(slices: Union[slice, tuple], n_parts: int):
177
177
  raise TypeError(f"slices type ({type(slices)}) is not handled. Must be a slice or an Iterable")
178
178
 
179
179
 
180
- def get_working_directory(obj: TomoObject) -> Optional[str]:
180
+ def get_working_directory(obj: TomoObject) -> Optional[str]: # noqa: PLR0911
181
181
  """
182
182
  return working directory for a specific TomoObject
183
183
  """
@@ -201,4 +201,4 @@ def get_working_directory(obj: TomoObject) -> Optional[str]:
201
201
  else:
202
202
  return os.path.abspath(os.path.dirname(obj.master_file))
203
203
  else:
204
- raise RuntimeError(f"obj type not handled ({type(obj)})")
204
+ raise RuntimeError(f"obj type not handled ({type(obj)})") # noqa: TRY004
@@ -21,6 +21,8 @@ def get_obj_constant_side_length(obj: Union[NXtomoScan, VolumeBase], axis: int)
21
21
  return obj.dim_1
22
22
  elif axis in (1, 2):
23
23
  return obj.dim_2
24
+ else:
25
+ raise ValueError(f"Axis ({axis}) not handled. Should be in (0, 1, 2)")
24
26
  elif isinstance(obj, VolumeBase) and axis == 0:
25
27
  return obj.get_volume_shape()[-1]
26
28
  else:
@@ -4,7 +4,6 @@ from typing import Union, Optional
4
4
  from tomoscan.identifier import BaseIdentifier
5
5
  from nabu.stitching.config import StitchingConfiguration
6
6
  from tomoscan.volumebase import VolumeBase
7
- from contextlib import AbstractContextManager
8
7
 
9
8
 
10
9
  class DumperBase:
@@ -96,7 +96,7 @@ class OutputVolumeContext(AbstractContextManager):
96
96
  if self._file_handler is not None:
97
97
  return self._file_handler.close()
98
98
  else:
99
- self._volume.save_data()
99
+ self._volume.save_data() # noqa: RET503
100
100
 
101
101
 
102
102
  class OutputVolumeNoDDContext(OutputVolumeContext):
@@ -13,11 +13,10 @@ from tomoscan.esrf import NXtomoScan
13
13
  from tomoscan.series import Series
14
14
  from tomoscan.volumebase import VolumeBase
15
15
  from tomoscan.esrf.volume import HDF5Volume
16
- from typing import Iterable
16
+ from collections.abc import Iterable
17
17
  from contextlib import AbstractContextManager
18
18
  from pyunitsystem.metricsystem import MetricSystem
19
19
  from nabu.stitching.config import (
20
- PostProcessedSingleAxisStitchingConfiguration,
21
20
  KEY_IMG_REG_METHOD,
22
21
  )
23
22
  from nabu.stitching.utils.utils import find_volumes_relative_shifts
@@ -422,7 +421,7 @@ class PostProcessingStitching(SingleAxisStitcher):
422
421
  [(abs(overlap), n_slices, self._stitching_constant_length) for overlap in self._axis_0_rel_final_shifts]
423
422
  )
424
423
 
425
- with self.dumper.OutputDatasetContext(**output_dataset_args):
424
+ with self.dumper.OutputDatasetContext(**output_dataset_args): # noqa: SIM117
426
425
  # note: output_dataset is a HDF5 dataset if final volume is an HDF5 volume else is a numpy array
427
426
  with _RawDatasetsContext(
428
427
  self._input_volumes,
@@ -518,7 +517,8 @@ class _RawDatasetsContext(AbstractContextManager):
518
517
  else:
519
518
  data = volume.load_data(store=False)
520
519
  if data is None:
521
- raise ValueError(f"No data found for volume {volume.get_identifier()}")
520
+ # TODO
521
+ raise ValueError(f"No data found for volume {volume.get_identifier()}") # noqa: TRY301
522
522
  if axis_1_need_padding:
523
523
  data = self.add_padding(data=data, axis_1_dim=axis_1_dim, alignment=self.alignment_axis_1)
524
524
  datasets.append(data)
@@ -526,7 +526,7 @@ class _RawDatasetsContext(AbstractContextManager):
526
526
  # if some errors happen during loading HDF5
527
527
  for file_handled in self.__file_handlers:
528
528
  file_handled.close()
529
- raise e
529
+ raise e # noqa: TRY201
530
530
 
531
531
  return datasets
532
532
 
@@ -534,7 +534,7 @@ class _RawDatasetsContext(AbstractContextManager):
534
534
  success = True
535
535
  for file_handler in self.__file_handlers:
536
536
  success = success and file_handler.close()
537
- if exc_type is None:
537
+ if exc_type is None: # noqa: RET503
538
538
  return success
539
539
 
540
540
  def add_padding(self, data: Union[h5py.Dataset, numpy.ndarray], axis_1_dim, alignment: AlignmentAxis1):
@@ -2,7 +2,7 @@ import numpy
2
2
  import logging
3
3
  import h5py
4
4
  import os
5
- from typing import Iterable
5
+ from collections.abc import Iterable
6
6
  from silx.io.url import DataUrl
7
7
  from silx.io.utils import get_data
8
8
  from datetime import datetime
@@ -40,7 +40,6 @@ class PreProcessingStitching(SingleAxisStitcher):
40
40
  """
41
41
 
42
42
  def __init__(self, configuration, progress=None) -> None:
43
- """ """
44
43
  if not isinstance(configuration, PreProcessedSingleAxisStitchingConfiguration):
45
44
  raise TypeError(
46
45
  f"configuration is expected to be an instance of {PreProcessedSingleAxisStitchingConfiguration}. Get {type(configuration)} instead"
@@ -526,9 +525,9 @@ class PreProcessingStitching(SingleAxisStitcher):
526
525
  if isinstance(slices, slice):
527
526
  return array[slices.start : slices.stop : 1]
528
527
  elif isinstance(slices, Iterable):
529
- return list([array[index] for index in slices])
528
+ return [array[index] for index in slices]
530
529
  else:
531
- raise RuntimeError("slices must be instance of a slice or of an iterable")
530
+ raise RuntimeError("slices must be instance of a slice or of an iterable") # noqa: TRY004
532
531
 
533
532
  nx_tomo.sample.rotation_angle = apply_slices_selection(
534
533
  array=nx_tomo.sample.rotation_angle, slices=self._slices_to_stitch
@@ -794,7 +793,7 @@ class PreProcessingStitching(SingleAxisStitcher):
794
793
  ):
795
794
  i_frame = 0
796
795
  _, set_of_compacted_slices = get_compacted_dataslices(scan_urls, return_url_set=True)
797
- for _, url in set_of_compacted_slices.items():
796
+ for url in set_of_compacted_slices.values():
798
797
  scan = scans[i_scan]
799
798
  url = DataUrl(
800
799
  file_path=url.file_path(),
@@ -886,6 +885,9 @@ class PreProcessingStitching(SingleAxisStitcher):
886
885
  """
887
886
  make sure reduced dark and flats are existing otherwise compute them
888
887
  """
888
+ # TODO
889
+ # ruff: noqa: SIM105, S110
890
+ # --
889
891
  for scan in self.series:
890
892
  try:
891
893
  reduced_darks, darks_infos = scan.load_reduced_darks(return_info=True)
@@ -896,7 +898,7 @@ class PreProcessingStitching(SingleAxisStitcher):
896
898
  try:
897
899
  # if we don't have write in the folder containing the .nx for example
898
900
  scan.save_reduced_darks(reduced_darks, darks_infos=darks_infos)
899
- except Exception as e:
901
+ except Exception:
900
902
  pass
901
903
  scan.set_reduced_darks(reduced_darks, darks_infos=darks_infos)
902
904
 
@@ -909,7 +911,7 @@ class PreProcessingStitching(SingleAxisStitcher):
909
911
  try:
910
912
  # if we don't have write in the folder containing the .nx for example
911
913
  scan.save_reduced_flats(reduced_flats, flats_infos=flats_infos)
912
- except Exception as e:
914
+ except Exception:
913
915
  pass
914
916
  scan.set_reduced_flats(reduced_flats, flats_infos=flats_infos)
915
917
 
@@ -979,7 +981,7 @@ class PreProcessingStitching(SingleAxisStitcher):
979
981
  ):
980
982
  i_frame = 0
981
983
  _, set_of_compacted_slices = get_compacted_dataslices(scan_urls, return_url_set=True)
982
- for _, url in set_of_compacted_slices.items():
984
+ for url in set_of_compacted_slices.values():
983
985
  scan = scans[i_scan]
984
986
  url = DataUrl(
985
987
  file_path=url.file_path(),
@@ -1000,12 +1002,12 @@ class PreProcessingStitching(SingleAxisStitcher):
1000
1002
 
1001
1003
  missing = []
1002
1004
  if len(scan.reduced_flats) == 0:
1003
- missing = "flats"
1005
+ missing.append("flats")
1004
1006
  if len(scan.reduced_darks) == 0:
1005
- missing = "darks"
1007
+ missing.append("darks")
1006
1008
 
1007
1009
  if len(missing) > 0:
1008
- _logger.warning(f"missing {'and'.join(missing)}. Unable to do flat field correction")
1010
+ _logger.warning(f"missing {' and '.join(missing)}. Unable to do flat field correction")
1009
1011
  ff_arrays = None
1010
1012
  data = raw_radios
1011
1013
  else:
@@ -1,8 +1,7 @@
1
- import h5py
2
1
  import numpy
3
2
  import logging
4
- from math import ceil
5
- from typing import Optional, Iterable, Union
3
+ from typing import Optional, Union
4
+ from collections.abc import Iterable
6
5
  from tomoscan.series import Series
7
6
  from tomoscan.identifier import BaseIdentifier
8
7
  from nabu.stitching.stitcher.base import _StitcherBase, get_obj_constant_side_length
@@ -38,7 +37,7 @@ class _SingleAxisMetaClass(type):
38
37
  Metaclass for single axis stitcher in order to aggregate dumper class and axis
39
38
  """
40
39
 
41
- def __new__(mcls, name, bases, attrs, axis=None, dumper_cls=None):
40
+ def __new__(mcls, name, bases, attrs, axis=None, dumper_cls=None): # noqa: N804
42
41
  mcls = super().__new__(mcls, name, bases, attrs)
43
42
  mcls._axis = axis
44
43
  mcls._dumperCls = dumper_cls
@@ -1,3 +1,4 @@
1
+ # ruff: noqa: N999
1
2
  import numpy
2
3
  from math import ceil
3
4
  from typing import Union, Optional
@@ -19,7 +20,7 @@ def stitch_raw_frames(
19
20
  pad_mode="constant",
20
21
  new_unstitched_axis_size: Optional[int] = None,
21
22
  ) -> numpy.ndarray:
22
- """
23
+ r"""
23
24
  stitches raw frames (already shifted and flat fielded !!!) together using
24
25
  raw stitching (no pixel interpolation, y_overlap_in_px is expected to be a int).
25
26
  Sttiching depends on the kernel used.
@@ -43,12 +43,10 @@ def test_stitching_config(stitching_type, option_level):
43
43
  stiching_config.dict_to_config_obj(config),
44
44
  stiching_config.PostProcessedSingleAxisStitchingConfiguration,
45
45
  )
46
- elif stitching_type is stiching_config.StitchingType.Z_PREPROC:
47
- assert isinstance(
48
- stiching_config.dict_to_config_obj(config),
49
- stiching_config.PreProcessedSingleAxisStitchingConfiguration,
50
- )
51
- elif stitching_type is stiching_config.StitchingType.Y_PREPROC:
46
+ elif (
47
+ stitching_type is stiching_config.StitchingType.Z_PREPROC
48
+ or stitching_type is stiching_config.StitchingType.Y_PREPROC
49
+ ):
52
50
  assert isinstance(
53
51
  stiching_config.dict_to_config_obj(config),
54
52
  stiching_config.PreProcessedSingleAxisStitchingConfiguration,
@@ -92,7 +90,7 @@ def test_stitching_config(stitching_type, option_level):
92
90
  "",
93
91
  None,
94
92
  "None",
95
- "",
93
+ "", # noqa: PT014
96
94
  "skimage",
97
95
  "nabu-fft",
98
96
  ),
@@ -176,7 +174,8 @@ def test_PreProcessedZStitchingConfiguration(
176
174
 
177
175
  from_dict = stiching_config.PreProcessedZStitchingConfiguration.from_dict(pre_process_config.to_dict())
178
176
  # workaround for scans because a new object is created each time
179
- pre_process_config.settle_inputs
177
+ # ???
178
+ pre_process_config.settle_inputs # noqa: B018
180
179
  assert len(from_dict.input_scans) == len(pre_process_config.input_scans)
181
180
  from_dict.input_scans = None
182
181
  pre_process_config.input_scans = None
@@ -1,6 +1,6 @@
1
1
  import numpy
2
2
  import pytest
3
- from nabu.stitching.sample_normalization import normalize_frame, SampleSide, Method
3
+ from nabu.stitching.sample_normalization import normalize_frame
4
4
 
5
5
 
6
6
  def test_normalize_frame():
@@ -1,5 +1,4 @@
1
1
  import os
2
- import numpy
3
2
  import pytest
4
3
  from tomoscan.esrf import NXtomoScan
5
4
  from tomoscan.esrf.volume import HDF5Volume
@@ -14,7 +13,7 @@ from nabu.stitching.slurm_utils import (
14
13
  from tomoscan.esrf.mock import MockNXtomo
15
14
 
16
15
  try:
17
- import sluurp
16
+ import sluurp # noqa: F401
18
17
  except ImportError:
19
18
  has_sluurp = False
20
19
  else:
@@ -770,6 +770,6 @@ def test_data_duplication(tmp_path, data_duplication):
770
770
  if not data_duplication:
771
771
  # make sure an error is raised if we try to ask for no data duplication and if we get some flips
772
772
  z_stich_config.flip_ud = (False, True, False)
773
- with pytest.raises(ValueError):
773
+ with pytest.raises(ValueError): # noqa: PT012
774
774
  stitcher = PostProcessZStitcherNoDD(z_stich_config, progress=None)
775
775
  stitcher.stitch()
@@ -5,11 +5,11 @@ import numpy
5
5
  import pytest
6
6
  from nabu.stitching.config import PreProcessedZStitchingConfiguration
7
7
  from nabu.stitching.config import KEY_IMG_REG_METHOD
8
- from nabu.stitching.overlap import ImageStichOverlapKernel, OverlapStitchingStrategy
8
+ from nabu.stitching.overlap import OverlapStitchingStrategy
9
9
  from nabu.stitching.z_stitching import (
10
10
  PreProcessZStitcher,
11
11
  )
12
- from nabu.stitching.stitcher_2D import stitch_raw_frames, get_overlap_areas
12
+ from nabu.stitching.stitcher_2D import get_overlap_areas
13
13
  from nxtomo.nxobject.nxdetector import ImageKey
14
14
  from nxtomo.utils.transformation import DetYFlipTransformation, DetZFlipTransformation
15
15
  from nxtomo.application.nxtomo import NXtomo
@@ -301,11 +301,11 @@ def test_DistributePreProcessZStitcher(tmp_path, configuration_dist):
301
301
  )
302
302
 
303
303
  if complete:
304
- len(final_nx_tomo.instrument.detector.data) == 128
304
+ assert len(final_nx_tomo.instrument.detector.data) == 100
305
305
  # test middle
306
306
  numpy.testing.assert_array_almost_equal(raw_data[1], final_nx_tomo.instrument.detector.data[1, :, :])
307
307
  else:
308
- len(final_nx_tomo.instrument.detector.data) == 3
308
+ assert len(final_nx_tomo.instrument.detector.data) == 3
309
309
  # test middle
310
310
  numpy.testing.assert_array_almost_equal(raw_data[49], final_nx_tomo.instrument.detector.data[1, :, :])
311
311
  # in the case of first, middle and last frames
File without changes
@@ -1,3 +1,4 @@
1
+ # noqa: N999
1
2
  import pytest
2
3
 
3
4
  from nabu.stitching.stitcher.single_axis import PROGRESS_BAR_STITCH_VOL_DESC