nabu 2025.1.0rc6__py3-none-any.whl → 2025.1.1__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.
nabu/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "2025.1.0-rc6"
1
+ __version__ = "2025.1.1"
2
2
  __nabu_modules__ = [
3
3
  "app",
4
4
  "cuda",
nabu/estimation/motion.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from enum import Enum
2
2
  from multiprocessing.pool import ThreadPool
3
+ from warnings import warn
3
4
  import numpy as np
4
5
  from ..utils import get_num_threads
5
6
 
@@ -218,12 +219,18 @@ class MotionEstimation:
218
219
  return _normalize_with_reference(a_all[-n_outward_projs:])
219
220
 
220
221
  def _configure_shifts_estimator(self, shifts_estimator, shifts_estimator_kwargs):
221
- self.shifts_estimator = shifts_estimator
222
222
  if shifts_estimator not in self._shifts_estimators_default_kwargs:
223
223
  raise NotImplementedError(
224
224
  f"Unknown estimator shifts '{shifts_estimator}', available are {list(self._shifts_estimators_default_kwargs.keys())}"
225
225
  )
226
- self._shifts_estimator_kwargs = self._shifts_estimators_default_kwargs[shifts_estimator].copy()
226
+ self.shifts_estimator = shifts_estimator
227
+ if self.shifts_estimator == "phase_cross_correlation" and phase_cross_correlation is None:
228
+ warn(
229
+ "shift estimator was set to 'phase_cross_correlation' but it requires scikit-image which is not available. Falling back to 'DetectorTranslationAlongBeam'",
230
+ Warning,
231
+ )
232
+ self.shifts_estimator = "DetectorTranslationAlongBeam"
233
+ self._shifts_estimator_kwargs = self._shifts_estimators_default_kwargs[self.shifts_estimator].copy()
227
234
  self._shifts_estimator_kwargs.update(shifts_estimator_kwargs or {})
228
235
 
229
236
  def _find_shifts(self, img1, img2):
nabu/io/cast_volume.py CHANGED
@@ -142,7 +142,7 @@ def cast_volume(
142
142
  remove_input_volume: bool = False,
143
143
  ) -> VolumeBase:
144
144
  """
145
- cast givent volume to output_volume of 'output_data_type' type
145
+ cast given volume to output_volume of 'output_data_type' type
146
146
 
147
147
  :param VolumeBase input_volume:
148
148
  :param VolumeBase output_volume:
@@ -231,6 +231,7 @@ def cast_volume(
231
231
  data_max=data_max,
232
232
  rescale_min_percentile=rescale_min_percentile,
233
233
  rescale_max_percentile=rescale_max_percentile,
234
+ default_value_for_nan=new_min,
234
235
  ).astype(output_data_type)
235
236
  else:
236
237
  output_slice = input_slice.astype(output_data_type)
@@ -268,25 +269,46 @@ def clamp_and_rescale_data(
268
269
  data_max=None,
269
270
  rescale_min_percentile=RESCALE_MIN_PERCENTILE,
270
271
  rescale_max_percentile=RESCALE_MAX_PERCENTILE,
272
+ default_value_for_nan=None,
273
+ do_float64=True,
271
274
  ):
272
275
  """
273
276
  rescale data to 'new_min', 'new_max'
274
277
 
275
- :param numpy.ndarray data: data to be rescaled
276
- :param dtype output_dtype: output dtype
277
- :param new_min: rescaled data new min (clamp min value)
278
- :param new_max: rescaled data new max (clamp max value)
279
- :param data_min: `data` min value to clamp to new_min. Any lower value will also be clamp to new_min.
280
- :param data_max: `data` max value to clamp to new_max. Any hight value will also be clamp to new_max.
281
- :param rescale_min_percentile: if `data_min` is None will set data_min to 'rescale_min_percentile'
282
- :param rescale_max_percentile: if `data_max` is None will set data_min to 'rescale_max_percentile'
278
+ Parameters
279
+ ----------
280
+ data: numpy.ndarray
281
+ Data to be rescaled (image or volume)
282
+ new_min: scalar
283
+ Rescaled data new min (clamp min value)
284
+ new_max: scalar
285
+ Rescaled data new min (clamp max value)
286
+ data_min: scalar, optional
287
+ Data minimum value. If not provided, will re-compute the min() over data.
288
+ data_max: scalar, optional
289
+ Data maximum value. If not provided, will re-compute the min() over data.
290
+ rescale_min_percentile: scalar, optional
291
+ if `data_min` is None will set data_min to 'rescale_min_percentile'
292
+ rescale_max_percentile
293
+ if `data_max` is None will set data_min to 'rescale_max_percentile'
294
+ default_value_for_nan: scalar, optional
295
+ Value that will replace NaNs, if any. Default is None (keep NaNs, will likely raise an error)
296
+ do_float64
297
+ Whether to do internal computations in float64. Recommended when casting from float32 to int32 for example.
283
298
  """
299
+ if do_float64 and data.dtype.itemsize < 8:
300
+ data = numpy.float64(data)
284
301
  if data_min is None:
285
- data_min = numpy.percentile(data, rescale_min_percentile)
302
+ data_min = numpy.nanpercentile(data, rescale_min_percentile)
286
303
  if data_max is None:
287
- data_max = numpy.percentile(data, rescale_max_percentile)
304
+ data_max = numpy.nanpercentile(data, rescale_max_percentile)
288
305
  # rescale data
289
306
  rescaled_data = rescale_data(data, new_min=new_min, new_max=new_max, data_min=data_min, data_max=data_max)
307
+ # Handle NaNs
308
+ if default_value_for_nan is not None:
309
+ isnan_mask = numpy.isnan(rescaled_data)
310
+ if numpy.any(isnan_mask):
311
+ rescaled_data[isnan_mask] = default_value_for_nan
290
312
  # clamp data
291
313
  rescaled_data[rescaled_data < new_min] = new_min
292
314
  rescaled_data[rescaled_data > new_max] = new_max
nabu/misc/utils.py CHANGED
@@ -3,9 +3,9 @@ import numpy as np
3
3
 
4
4
  def rescale_data(data, new_min, new_max, data_min=None, data_max=None):
5
5
  if data_min is None:
6
- data_min = np.min(data)
6
+ data_min = np.nanmin(data)
7
7
  if data_max is None:
8
- data_max = np.max(data)
8
+ data_max = np.nanmax(data)
9
9
  return (new_max - new_min) / (data_max - data_min) * (data - data_min) + new_min
10
10
 
11
11
 
@@ -690,7 +690,7 @@ class CompositeCORFinder(CORFinderBase):
690
690
  tmp_sy, ovsd_sx = radio1.shape
691
691
  assert orig_sy == tmp_sy and orig_ovsd_sx == ovsd_sx, "this should not happen"
692
692
 
693
- cor_side = self.cor_options["side"]
693
+ cor_side = self._lookup_side if self._lookup_side is not None else self.cor_options["side"]
694
694
  if cor_side == "center":
695
695
  overlap_min = max(round(ovsd_sx - ovsd_sx / 3), 4)
696
696
  overlap_max = min(round(ovsd_sx + ovsd_sx / 3), 2 * ovsd_sx - 4)
@@ -879,9 +879,10 @@ class ChunkedPipeline:
879
879
  data_vwu[i] = self.radios[:, i, :]
880
880
  # ---
881
881
 
882
- return self.reconstruction.reconstruct( # pylint: disable=E1101
882
+ rec = self.reconstruction.reconstruct( # pylint: disable=E1101
883
883
  data_vwu,
884
884
  )
885
+ return rec.astype("f") # corrct uses float64 data
885
886
 
886
887
  @pipeline_step("histogram", "Computing histogram")
887
888
  def _compute_histogram(self, data=None):
@@ -103,7 +103,7 @@ nabu_config = {
103
103
  },
104
104
  "detector_distortion_correction": {
105
105
  "default": "",
106
- "help": "Apply coordinate transformation on the raw data, at the reading stage. Default (empty) is None. Available are: None, identity(for testing the pipeline), map_xz. This latter method requires two URLs being passed by detector_distortion_correction_options: map_x and map_z pointing to two 2D arrays containing the position where each pixel can be interpolated at in the raw data",
106
+ "help": "Apply coordinate transformation on the raw data, at the reading stage. Default (empty) is None.\n Available are: None, identity(for testing the pipeline), map_xz.\n This latter method requires two URLs being passed by detector_distortion_correction_options: map_x and map_z pointing to two 2D arrays containing the position where each pixel can be interpolated at in the raw data",
107
107
  "validator": detector_distortion_correction_validator,
108
108
  "type": "advanced",
109
109
  },
@@ -367,6 +367,7 @@ class FullFieldReconstructor:
367
367
  # overlap = ceil(delta_z * d2 / (d1 + d2)) # sqrt(2) missing ?
368
368
 
369
369
  max_overlap = ceil(n_z * d2 / (d1 + d2)) # sqrt(2) missing ?
370
+ max_overlap = max(max_overlap, 10) # use at least 10 pixels
370
371
 
371
372
  return (max_overlap, 0)
372
373
 
@@ -0,0 +1,30 @@
1
+ import numpy as np
2
+
3
+
4
+ class IterativeBase:
5
+
6
+ backend = None # placeholder
7
+ implementation = None # placeholder
8
+
9
+ default_extra_options = {
10
+ "axis_correction": None,
11
+ "centered_axis": False,
12
+ "clip_outer_circle": False,
13
+ "scale_factor": None,
14
+ "outer_circle_value": 0.0,
15
+ }
16
+
17
+ backend_processing_class = ProcessingBase
18
+
19
+ def __init__(
20
+ self,
21
+ sino_shape,
22
+ angles=None,
23
+ rot_center=None,
24
+ halftomo=False,
25
+ filter_name=None,
26
+ slice_roi=None,
27
+ scale_factor=None,
28
+ extra_options=None,
29
+ backend_options=None,
30
+ ): ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nabu
3
- Version: 2025.1.0rc6
3
+ Version: 2025.1.1
4
4
  Summary: Nabu - Tomography software
5
5
  Author-email: Pierre Paleo <pierre.paleo@esrf.fr>, Henri Payno <henri.payno@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>
6
6
  Maintainer-email: Pierre Paleo <pierre.paleo@esrf.fr>
@@ -1,7 +1,7 @@
1
1
  doc/conf.py,sha256=3xtCarCHrXPr50GbeRDuH-o3Jzojw7mpr7vpGfZPLAE,3787
2
2
  doc/create_conf_doc.py,sha256=IVOdP70KvbW9WS_UQu3Iyd0YfS60E2fJ5IDtQ_s4cDw,1143
3
3
  doc/get_mathjax.py,sha256=VIvKRCdDuF2VoY8JD3mSey9XX13AZMmwTJBHdt1tUs4,1012
4
- nabu/__init__.py,sha256=EGKVb44QFboUSoFCqFcSfj8VLtWXW3czbgYHuNnE_-I,274
4
+ nabu/__init__.py,sha256=cquIT6AKfmVtn7EkXyjYjG8hLJ0tMLDKmD2vmBh_vnY,270
5
5
  nabu/tests.py,sha256=hOJD1GGxn_KE1bWMoxfjnjzI7d9JBUpoc9B2_tVFiEk,1370
6
6
  nabu/testutils.py,sha256=4I62IP3VLOJx8JvGBgY1t4i4CiJMWfT_aUopxg39JIM,10047
7
7
  nabu/utils.py,sha256=tJI64BNXMhD6W293fwwcgf9bvTalYG_5AwVGYkgi6tU,27179
@@ -69,7 +69,7 @@ nabu/estimation/cor.py,sha256=8RsyZ_MYT04EWvP2tLThftn_bD3cz9-uWo8D5FpXLKQ,50353
69
69
  nabu/estimation/cor_sino.py,sha256=qN6y16UVqoDX696JYyn3iWXDxQo0FMcFTuGbT92BW_s,18959
70
70
  nabu/estimation/distortion.py,sha256=DEXizQpgHBXmrhbQ0kuEchicxmiDgmU2qrh8bCgSezg,4701
71
71
  nabu/estimation/focus.py,sha256=CdtMFk6Xt4qq1JwwKDmDcVCeVocz-mpV0saikO0B1mc,17995
72
- nabu/estimation/motion.py,sha256=8fgwGsJMZleUugCCMRyZ2Zfi6-fWp-_dJpUnvetxGvk,26501
72
+ nabu/estimation/motion.py,sha256=5p6Tsea-77Kc9QaYKkD33aQ_ZA5mSO1arHQ4tjclEJ0,26927
73
73
  nabu/estimation/tilt.py,sha256=6R8l8gnf00m-xdgLhvQmkvZ3lIO_8hDglNsFjzlzZ4E,8834
74
74
  nabu/estimation/translation.py,sha256=qoxT8VT38TZqrqLRwOef7-wBE5OeEObp_Qy9T2De2Do,10184
75
75
  nabu/estimation/utils.py,sha256=31d17Ng__NxcLOtGXPmbPPW1veh1m0poCvRgDCJssUA,347
@@ -81,7 +81,7 @@ nabu/estimation/tests/test_motion_estimation.py,sha256=WKUpkVand8VszoBIvsaEnhKqv
81
81
  nabu/estimation/tests/test_tilt.py,sha256=KIgTJqQvNfWndm8f3aRSdznWFl3AdQhYXiZPKLseYOs,1672
82
82
  nabu/estimation/tests/test_translation.py,sha256=RkOnCYgk9DZGKlIka1snqTv4wbIz_nG7-EHAxnBHsJU,2999
83
83
  nabu/io/__init__.py,sha256=AbQgj4-fCCHOKynO_PyAR9ejnFSuWKgroxxhxWVpjyQ,120
84
- nabu/io/cast_volume.py,sha256=eJuiKuZILD3xClUtYOjCqmwnbW12gwg-gJTzj606u_Y,21499
84
+ nabu/io/cast_volume.py,sha256=y7MRsrC5WBbY0BtlnqQJWxByEP43Gq1qrq969bADGBI,22220
85
85
  nabu/io/detector_distortion.py,sha256=qO1Z6gejkBrixThvU_sLwH3UfLAe8aAO63YQ8z7PH78,11750
86
86
  nabu/io/reader.py,sha256=CRQfzLqG10QNzKpPY1j3z2toEAti2bNgImMwWnHQfVE,41775
87
87
  nabu/io/reader_helical.py,sha256=q3LOmu6F_4Uxi3rZZWJ-rsix2Lgu_saXXdiJF8TLi24,4533
@@ -109,7 +109,7 @@ nabu/misc/transpose.py,sha256=ogJ1PPYO0sOPUfCgjk-Ho5cTjlBbP-KXGqhCgTj75DY,223
109
109
  nabu/misc/unsharp.py,sha256=3xYsdiLTqTDlE8G-tIY7EeTf3nKxPrvMHOnXgkcKWvU,209
110
110
  nabu/misc/unsharp_cuda.py,sha256=-csDxfQt_naYn5O8fOxksYNqyFKxbF8lV7yXlPd2XoM,235
111
111
  nabu/misc/unsharp_opencl.py,sha256=HCPoobPwi2LEAfqGQ2qekjQi6G2VDKmqJQZTDXySv1Y,252
112
- nabu/misc/utils.py,sha256=s8ACtKdw9rTmlD0APdrpeo_ZIneKsTv2Xq3X2TRxCRk,3898
112
+ nabu/misc/utils.py,sha256=b0JlnRmhEyx-9SBycRGQxPqNa25uTZqOFtGOF3Fyxdg,3904
113
113
  nabu/misc/tests/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
114
114
  nabu/misc/tests/test_binning.py,sha256=vcZZINi_v_KOw4DMqLIgPlF-CwLTG102Yf7dMQ5_SEo,1890
115
115
  nabu/misc/tests/test_interpolation.py,sha256=H8ZJ7dppCcpxVa9wOBkJ9U0mymH5lGyCJ0LZCYIK8PE,2389
@@ -134,21 +134,21 @@ nabu/pipeline/config_validators.py,sha256=Wx9nnUpfxTJ8H2ODkUyjImTtJS9V68TafLH1Te
134
134
  nabu/pipeline/datadump.py,sha256=tKW-Dl28FU2vf1OuIie_YI1-GT1DMreis57sOR-DuGU,7026
135
135
  nabu/pipeline/dataset_validator.py,sha256=etQw9NC_YGsdWCgjsn8aJ3WfvcRuJlLVZlWoqhvvo-8,9263
136
136
  nabu/pipeline/detector_distortion_provider.py,sha256=ru1AxbcuO-FA8FYooPBWgp1lzdSDUtzFUC1A_sS8jME,920
137
- nabu/pipeline/estimators.py,sha256=ALzlcBxaVMt7OprEgndfBE_csuv9aKZax3erD3nBWU0,51786
137
+ nabu/pipeline/estimators.py,sha256=GhBs5bW4J2ZgDK30Pgg-hcb-B6SYQUPIP5sZmQhBpYA,51842
138
138
  nabu/pipeline/params.py,sha256=UKMQWFQnrlNMW5aIGty-JoGmBdkS6tpoAXCjW8n6FX8,4229
139
139
  nabu/pipeline/processconfig.py,sha256=3xx2Lc8uEzPAqSMwUncr4RCiCtKn2c7wnXXbPSn8GNo,7719
140
140
  nabu/pipeline/reader.py,sha256=wkxPHYOi_C8dHNc7kddB8AMtFuW7GjsP_tm6SJeHlEY,4792
141
141
  nabu/pipeline/utils.py,sha256=5GGhT9Wu7tHDlF3w7YNjTTYkNBl5xHa9EcRZSGFUWtM,3538
142
142
  nabu/pipeline/writer.py,sha256=NVeAtkWDtXg5UJ4C3wsbkfM23ZnK64atCWl8tjmjsuY,8166
143
143
  nabu/pipeline/fullfield/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
144
- nabu/pipeline/fullfield/chunked.py,sha256=gEm9XYk1MhNQBi-2VSVrXKQD55XmLPQAoHn9sCsEDIc,43272
144
+ nabu/pipeline/fullfield/chunked.py,sha256=5dGoP_vCajI7kl2b9AysufG6DV1gdX9uvF0THrhNDaA,43330
145
145
  nabu/pipeline/fullfield/chunked_cuda.py,sha256=US5prrhNjsx3QVHkY5duQp8uFcGdgYEPzVS7nfWkJRw,6047
146
146
  nabu/pipeline/fullfield/computations.py,sha256=uqf7LvuDPm7n51BpP8eb8vTewDgRFyzSDP249g3FWBE,10098
147
147
  nabu/pipeline/fullfield/dataset_validator.py,sha256=HK_bmlII9pc59PXCgKJOyLv7Xu3DYv_jbH3RmQSgzvI,2933
148
148
  nabu/pipeline/fullfield/get_double_flatfield.py,sha256=uYFDAii6Nw4RCUQO_6Id6tXLdmtVbj_pxAHQWennSeE,5411
149
- nabu/pipeline/fullfield/nabu_config.py,sha256=F1E4KwHTfw6tynBnBjvr1F6tflIFsvDp8Pyop7xNmGg,33146
149
+ nabu/pipeline/fullfield/nabu_config.py,sha256=XcvPpJjyTmp8QSWK1lcNWRa1ybL0AQ0poj3O_CgDYtM,33150
150
150
  nabu/pipeline/fullfield/processconfig.py,sha256=72hjxgClKcxmzypVpvcWzkzoXP7Ypu5VpRxMjYQVnJQ,38461
151
- nabu/pipeline/fullfield/reconstruction.py,sha256=cljRyxD8rvZ5qDws_5AwChi7P-5T_0SSXsGkYUGOVb8,38006
151
+ nabu/pipeline/fullfield/reconstruction.py,sha256=Fi3GCsVjO3CpYIWZM-4i6S2UOzG7iqVeukQ375j09Pg,38075
152
152
  nabu/pipeline/helical/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
153
  nabu/pipeline/helical/dataset_validator.py,sha256=HdKjUSj3PIpJb1dKSzJg8s4zXbAnMPWaPn8kvp_xQEs,657
154
154
  nabu/pipeline/helical/fbp.py,sha256=MKn587bO5Lj7yFu-Sll2RkOIY5r3rC-fmC10SzFU5i0,5841
@@ -235,6 +235,7 @@ nabu/reconstruction/filtering.py,sha256=monJnA_kk9k_Gy7bMAos9I-XgU8czWhf9vBth6ik
235
235
  nabu/reconstruction/filtering_cuda.py,sha256=_S-BZMhtnNt8ugePSmf-LF7JvMPCOyGPUMSseymgwZw,4019
236
236
  nabu/reconstruction/filtering_opencl.py,sha256=v-sUzbnRp6M1B221F-iSh-crBCGknjHYYsjFs05VhDY,3788
237
237
  nabu/reconstruction/hbp.py,sha256=Qll7i20LWxUo1-SHRxemkYAolBTP8HScwt1OvWmD2r0,18642
238
+ nabu/reconstruction/iterative.py,sha256=urZg_Aj3P2wGfsbjlyvmOvf2yd-kXNt_f4Sjlj6oxhE,637
238
239
  nabu/reconstruction/mlem.py,sha256=wgC2pKl6RKB-f2318worB9VE-qCGoQcz24aKbtkrJos,5794
239
240
  nabu/reconstruction/projection.py,sha256=SNocaOY9HuNiHs-VxkW9IS707JPJnd3sDjAbf7aIw2E,9081
240
241
  nabu/reconstruction/reconstructor.py,sha256=16xxHcK4iie-uh-trf6x_IuvgxJKBvQRTE5B8tnc4F8,7358
@@ -318,9 +319,9 @@ nabu/thirdparty/pore3d_deringer_munch.py,sha256=o4bisnFc-wMjuohWBT8wgWmfNehPQGtC
318
319
  nabu/thirdparty/tomocupy_remove_stripe.py,sha256=Khe4zFf0kRzu65Yxnvq58gt1ljOztqJGdMDhVAiM7lM,24363
319
320
  nabu/thirdparty/tomopy_phase.py,sha256=hK4oPpkogLOhv23XzzEXQY2u3r8fJvASY_bINVs6ERE,8634
320
321
  nabu/thirdparty/tomwer_load_flats_darks.py,sha256=ZNoVAinUb_wGYbfvs_4BVnWsjsQmNxSvCh1bWhR2WWg,5611
321
- nabu-2025.1.0rc6.dist-info/licenses/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
322
- nabu-2025.1.0rc6.dist-info/METADATA,sha256=yA0Om_mA72YwMBuAcOrLfV5_PjGK375QUsRrnp1gE50,4274
323
- nabu-2025.1.0rc6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
324
- nabu-2025.1.0rc6.dist-info/entry_points.txt,sha256=YxzCY5CNQ1XHrIGbRKg-BgC1Jy7QaCITdITpyhhxpZU,1338
325
- nabu-2025.1.0rc6.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
326
- nabu-2025.1.0rc6.dist-info/RECORD,,
322
+ nabu-2025.1.1.dist-info/licenses/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
323
+ nabu-2025.1.1.dist-info/METADATA,sha256=3wyX7ZF2Sqn5Z_w80g6_dvSEeT6Uct06l8DvCoYRxpA,4271
324
+ nabu-2025.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
325
+ nabu-2025.1.1.dist-info/entry_points.txt,sha256=YxzCY5CNQ1XHrIGbRKg-BgC1Jy7QaCITdITpyhhxpZU,1338
326
+ nabu-2025.1.1.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
327
+ nabu-2025.1.1.dist-info/RECORD,,