cloudnetpy 1.83.0__py3-none-any.whl → 1.84.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.
@@ -93,7 +93,7 @@ def generate_categorize(
93
93
  if data.disdrometer is not None:
94
94
  data.disdrometer.interpolate_to_grid(time)
95
95
  if data.mwr is not None:
96
- data.mwr.rebin_to_grid(time)
96
+ data.mwr.interpolate_to_grid(time)
97
97
  data.model.calc_attenuations(data.radar.radar_frequency)
98
98
  data.model.interpolate_to_common_height()
99
99
  model_gap_ind = data.model.interpolate_to_grid(time, height)
@@ -1,16 +1,12 @@
1
1
  """Mwr module, containing the :class:`Mwr` class."""
2
2
 
3
- import logging
4
3
  from os import PathLike
5
4
 
6
- import numpy as np
7
5
  import numpy.typing as npt
8
- from numpy import ma
9
- from scipy.interpolate import interp1d
10
6
 
11
- from cloudnetpy.categorize.lidar import get_gap_ind
12
7
  from cloudnetpy.datasource import DataSource
13
8
  from cloudnetpy.exceptions import DisdrometerDataError
9
+ from cloudnetpy.utils import interpolate_1d
14
10
 
15
11
 
16
12
  class Disdrometer(DataSource):
@@ -28,7 +24,9 @@ class Disdrometer(DataSource):
28
24
 
29
25
  def interpolate_to_grid(self, time_grid: npt.NDArray) -> None:
30
26
  for key, array in self.data.items():
31
- self.data[key].data = self._interpolate(array.data, time_grid)
27
+ self.data[key].data = interpolate_1d(
28
+ self.time, array.data, time_grid, max_time=1
29
+ )
32
30
 
33
31
  def _init_rainfall_rate(self) -> None:
34
32
  keys = ("rainfall_rate", "n_particles")
@@ -37,24 +35,3 @@ class Disdrometer(DataSource):
37
35
  msg = f"variable {key} is missing"
38
36
  raise DisdrometerDataError(msg)
39
37
  self.append_data(self.dataset.variables[key][:], key)
40
-
41
- def _interpolate(self, y: ma.MaskedArray, x_new: npt.NDArray) -> npt.NDArray:
42
- time = self.time
43
- mask = ma.getmask(y)
44
- if mask is not ma.nomask:
45
- if np.all(mask):
46
- return ma.masked_all(x_new.shape)
47
- not_masked = ~mask
48
- y = y[not_masked]
49
- time = time[not_masked]
50
- fun = interp1d(time, y, fill_value="extrapolate")
51
- interpolated_array = ma.array(fun(x_new))
52
- max_time = 1 / 60 # min -> fraction hour
53
- mask_ind = get_gap_ind(time, x_new, max_time)
54
-
55
- if len(mask_ind) > 0:
56
- msg = f"Unable to interpolate disdrometer for {len(mask_ind)} time steps"
57
- logging.warning(msg)
58
- interpolated_array[mask_ind] = ma.masked
59
-
60
- return interpolated_array
@@ -4,12 +4,11 @@ import logging
4
4
  from os import PathLike
5
5
  from typing import Literal
6
6
 
7
- import numpy as np
8
7
  import numpy.typing as npt
9
8
  from numpy import ma
10
9
 
11
10
  from cloudnetpy.datasource import DataSource
12
- from cloudnetpy.utils import interpolate_2d_nearest
11
+ from cloudnetpy.utils import get_gap_ind, interpolate_2d_nearest
13
12
 
14
13
 
15
14
  class Lidar(DataSource):
@@ -70,13 +69,3 @@ class Lidar(DataSource):
70
69
  self.append_data(float(self.getvar("wavelength")), "lidar_wavelength")
71
70
  self.append_data(0.5, "beta_error")
72
71
  self.append_data(3.0, "beta_bias")
73
-
74
-
75
- def get_gap_ind(
76
- grid: npt.NDArray, new_grid: npt.NDArray, threshold: float
77
- ) -> list[int]:
78
- return [
79
- ind
80
- for ind, value in enumerate(new_grid)
81
- if np.min(np.abs(grid - value)) > threshold
82
- ]
@@ -8,6 +8,7 @@ import numpy.typing as npt
8
8
  from cloudnetpy import utils
9
9
  from cloudnetpy.constants import G_TO_KG
10
10
  from cloudnetpy.datasource import DataSource
11
+ from cloudnetpy.utils import interpolate_1d
11
12
 
12
13
 
13
14
  class Mwr(DataSource):
@@ -23,15 +24,11 @@ class Mwr(DataSource):
23
24
  self._init_lwp_data()
24
25
  self._init_lwp_error()
25
26
 
26
- def rebin_to_grid(self, time_grid: npt.NDArray) -> None:
27
- """Approximates lwp and its error in a grid using mean.
28
-
29
- Args:
30
- time_grid: 1D target time grid.
31
-
32
- """
33
- for array in self.data.values():
34
- array.rebin_data(self.time, time_grid)
27
+ def interpolate_to_grid(self, time_grid: npt.NDArray, max_time: float = 1) -> None:
28
+ for key, array in self.data.items():
29
+ self.data[key].data = interpolate_1d(
30
+ self.time, array.data, time_grid, max_time=max_time
31
+ )
35
32
 
36
33
  def _init_lwp_data(self) -> None:
37
34
  lwp = self.dataset.variables["lwp"][:]
@@ -205,6 +205,7 @@ TOA5_HEADERS = {
205
205
  "precipitation": "_rain_accum",
206
206
  "rain accum [mm]": "_rain_accum",
207
207
  "weatherCodeWaWa": "synop_WaWa",
208
+ "wawa": "synop_WaWa",
208
209
  "weather_code_wawa": "synop_WaWa",
209
210
  "radarReflectivity": "radar_reflectivity",
210
211
  "radar_reflectivity": "radar_reflectivity",
@@ -70,6 +70,8 @@ def ws2nc(
70
70
  ws = LimassolWS(weather_station_file, site_meta)
71
71
  elif site_meta["name"] == "L'Aquila":
72
72
  ws = LAquilaWS(weather_station_file, site_meta)
73
+ elif site_meta["name"] == "Maïdo Observatory":
74
+ ws = MaidoWS(weather_station_file, site_meta)
73
75
  else:
74
76
  msg = "Unsupported site"
75
77
  raise ValueError(msg)
@@ -162,6 +164,26 @@ class WS(CSVFile):
162
164
 
163
165
 
164
166
  class PalaiseauWS(WS):
167
+ expected_header_identifiers: tuple[str, ...] = (
168
+ "DateTime(yyyy-mm-ddThh:mm:ssZ)",
169
+ "Windspeed(m/s)",
170
+ "Winddirection(deg",
171
+ "Airtemperature",
172
+ "Relativehumidity(%)",
173
+ "Pressure(hPa)",
174
+ "Precipitationrate(mm/min)",
175
+ "precipitation",
176
+ )
177
+ keys: tuple[str, ...] = (
178
+ "wind_speed",
179
+ "wind_direction",
180
+ "air_temperature",
181
+ "relative_humidity",
182
+ "air_pressure",
183
+ "rainfall_rate",
184
+ "rainfall_amount",
185
+ )
186
+
165
187
  def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict) -> None:
166
188
  super().__init__(site_meta)
167
189
  self.filenames = filenames
@@ -175,16 +197,16 @@ class PalaiseauWS(WS):
175
197
  for row in data:
176
198
  if not (columns := row.split()):
177
199
  continue
178
- if row.startswith("#"):
179
- header_row = "".join(columns)
180
- if header_row not in header:
181
- header.append(header_row)
182
- else:
200
+ if re.match(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", columns[0]):
183
201
  timestamp = datetime.datetime.strptime(
184
202
  columns[0], "%Y-%m-%dT%H:%M:%SZ"
185
203
  ).replace(tzinfo=datetime.timezone.utc)
186
204
  values.append([timestamp] + [float(x) for x in columns[1:]])
187
205
  timestamps.append(timestamp)
206
+ else:
207
+ header_row = "".join(columns)
208
+ if header_row not in header:
209
+ header.append(header_row)
188
210
 
189
211
  self._validate_header(header)
190
212
  return {"time": timestamps, "values": values}
@@ -204,16 +226,9 @@ class PalaiseauWS(WS):
204
226
  ]
205
227
 
206
228
  def add_data(self) -> None:
207
- keys = (
208
- "wind_speed",
209
- "wind_direction",
210
- "air_temperature",
211
- "relative_humidity",
212
- "air_pressure",
213
- "rainfall_rate",
214
- "rainfall_amount",
215
- )
216
- for ind, key in enumerate(keys):
229
+ for ind, key in enumerate(self.keys):
230
+ if key.startswith("_"):
231
+ continue
217
232
  array = [row[ind + 1] for row in self._data["values"]]
218
233
  array_masked = ma.masked_invalid(array)
219
234
  self.data[key] = CloudnetArray(array_masked, key)
@@ -223,27 +238,46 @@ class PalaiseauWS(WS):
223
238
  self.data["rainfall_amount"][:] / 1000
224
239
  ) # mm -> m
225
240
 
226
- @staticmethod
227
- def _validate_header(header: list[str]) -> None:
228
- expected_identifiers = [
229
- "DateTime(yyyy-mm-ddThh:mm:ssZ)",
230
- "Windspeed(m/s)",
231
- "Winddirection(deg",
232
- "Airtemperature",
233
- "Relativehumidity(%)",
234
- "Pressure(hPa)",
235
- "Precipitationrate(mm/min)",
236
- "precipitation",
237
- ]
241
+ def _validate_header(self, header: list[str]) -> None:
238
242
  column_titles = [row for row in header if "Col." in row]
239
243
  error_msg = "Unexpected weather station file format"
240
- if len(column_titles) != len(expected_identifiers):
244
+ if len(column_titles) != len(self.expected_header_identifiers):
241
245
  raise ValueError(error_msg)
242
- for title, identifier in zip(column_titles, expected_identifiers, strict=True):
246
+ for title, identifier in zip(
247
+ column_titles, self.expected_header_identifiers, strict=True
248
+ ):
243
249
  if identifier not in title:
244
250
  raise ValueError(error_msg)
245
251
 
246
252
 
253
+ class MaidoWS(PalaiseauWS):
254
+ expected_header_identifiers = (
255
+ "DateTimeyyyy-mm-ddThh:mm:ssZ",
256
+ "Winddirection-average",
257
+ "Windspeed-maximumvalue(m/s)",
258
+ "Windspeed-average(m/s)",
259
+ "Pressure-average(hPa)",
260
+ "Relativehumidity-maximumvalue(%)",
261
+ "Relativehumidity-average(%)",
262
+ "Airtemperature-minimumvalue",
263
+ "Airtemperature-average",
264
+ )
265
+
266
+ keys = (
267
+ "wind_direction",
268
+ "_wind_speed_max",
269
+ "wind_speed",
270
+ "air_pressure",
271
+ "_relative_humidity_max",
272
+ "relative_humidity",
273
+ "_air_temperature_min",
274
+ "air_temperature",
275
+ )
276
+
277
+ def convert_rainfall_amount(self) -> None:
278
+ pass
279
+
280
+
247
281
  class BucharestWS(PalaiseauWS):
248
282
  def convert_rainfall_rate(self) -> None:
249
283
  rainfall_rate = self.data["rainfall_rate"][:]
cloudnetpy/utils.py CHANGED
@@ -3,6 +3,7 @@
3
3
  import base64
4
4
  import datetime
5
5
  import hashlib
6
+ import logging
6
7
  import os
7
8
  import re
8
9
  import textwrap
@@ -17,7 +18,12 @@ import numpy as np
17
18
  import numpy.typing as npt
18
19
  from numpy import ma
19
20
  from scipy import ndimage, stats
20
- from scipy.interpolate import RectBivariateSpline, RegularGridInterpolator, griddata
21
+ from scipy.interpolate import (
22
+ RectBivariateSpline,
23
+ RegularGridInterpolator,
24
+ griddata,
25
+ interp1d,
26
+ )
21
27
 
22
28
  from cloudnetpy.cloudnetarray import CloudnetArray
23
29
  from cloudnetpy.constants import SEC_IN_DAY, SEC_IN_HOUR, SEC_IN_MINUTE
@@ -413,6 +419,55 @@ def interpolate_2d_nearest(
413
419
  return fun((xx, yy)).T
414
420
 
415
421
 
422
+ def interpolate_1d(
423
+ time: npt.NDArray, y: ma.MaskedArray, time_new: npt.NDArray, max_time: float
424
+ ) -> npt.NDArray:
425
+ """1D linear interpolation preserving the mask.
426
+
427
+ Args:
428
+ time: 1D array in fraction hour.
429
+ y: 1D masked array, data values.
430
+ time_new: 1D array, new time coordinates.
431
+ max_time: Maximum allowed gap in minutes. Values outside this gap will
432
+ be masked.
433
+ """
434
+ if np.max(time) > 24 or np.min(time) < 0:
435
+ msg = "Time vector must be in fraction hours between 0 and 24"
436
+ raise ValueError(msg)
437
+ if ma.is_masked(y):
438
+ if y.mask.all():
439
+ return ma.masked_all(time_new.shape)
440
+ time = time[~y.mask]
441
+ y = y[~y.mask]
442
+ fun = interp1d(time, y, fill_value=(y[0], y[-1]), bounds_error=False)
443
+ interpolated = ma.array(fun(time_new))
444
+ bad_idx = get_gap_ind(time, time_new, max_time / 60)
445
+
446
+ if len(bad_idx) > 0:
447
+ msg = f"Unable to interpolate for {len(bad_idx)} time steps"
448
+ logging.warning(msg)
449
+ interpolated[bad_idx] = ma.masked
450
+
451
+ return interpolated
452
+
453
+
454
+ def get_gap_ind(
455
+ grid: npt.NDArray, new_grid: npt.NDArray, threshold: float
456
+ ) -> list[int]:
457
+ """Finds indices in new_grid that are too far from grid."""
458
+ if grid.size == 0:
459
+ return list(range(len(new_grid)))
460
+ idxs = np.searchsorted(grid, new_grid)
461
+ left_dist = np.where(idxs > 0, np.abs(new_grid - grid[idxs - 1]), np.inf)
462
+ right_dist = np.where(
463
+ idxs < len(grid),
464
+ np.abs(new_grid - grid[np.clip(idxs, 0, len(grid) - 1)]),
465
+ np.inf,
466
+ )
467
+ nearest = np.minimum(left_dist, right_dist)
468
+ return np.where(nearest > threshold)[0].tolist()
469
+
470
+
416
471
  def calc_relative_error(reference: npt.NDArray, array: npt.NDArray) -> npt.NDArray:
417
472
  """Calculates relative error (%)."""
418
473
  return ((array - reference) / reference) * 100
cloudnetpy/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  MAJOR = 1
2
- MINOR = 83
2
+ MINOR = 84
3
3
  PATCH = 0
4
4
  __version__ = f"{MAJOR}.{MINOR}.{PATCH}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudnetpy
3
- Version: 1.83.0
3
+ Version: 1.84.0
4
4
  Summary: Python package for Cloudnet processing
5
5
  Author: Simo Tukiainen
6
6
  License: MIT License
@@ -8,24 +8,24 @@ cloudnetpy/exceptions.py,sha256=ZB3aUwjVRznR0CcZ5sZHrB0yz13URDf52Ksv7G7C7EA,1817
8
8
  cloudnetpy/metadata.py,sha256=CFpXmdEkVPzvLPv2xHIR-aMMQ-TR26KfESYw-98j7sk,7213
9
9
  cloudnetpy/output.py,sha256=0bybnILsgKHWIuw2GYkqTz2iMCJDZLUN25IQ9o_v3Cg,14968
10
10
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- cloudnetpy/utils.py,sha256=Qv60_vxknB3f2S3EFtyoD2CBY3N6mgDRObNp2u1oYUc,31806
12
- cloudnetpy/version.py,sha256=eZHEAex9xrlQzhoqlO0MSLCFCdaJCCetQ0O35RSY7VM,72
11
+ cloudnetpy/utils.py,sha256=O5kEXMt03fFKabPxRiCfuahVfTqa4fWWZ11orQnQeXU,33530
12
+ cloudnetpy/version.py,sha256=muQUQb3xKBF1loNyy50A6CariaWU5ZNM_Ff1hDxBTqA,72
13
13
  cloudnetpy/categorize/__init__.py,sha256=gtvzWr0IDRn2oA6yHBvinEhTGTuub-JkrOv93lBsgrE,61
14
14
  cloudnetpy/categorize/atmos_utils.py,sha256=uWc9TABVYPI0sn4H5Az9Jf6NVRaWyEKIi17f0pAJQxE,10679
15
15
  cloudnetpy/categorize/attenuation.py,sha256=Y_-fzmQTltWTqIZTulJhovC7a6ifpMcaAazDJcnMIOc,990
16
- cloudnetpy/categorize/categorize.py,sha256=NtSnLblVBgUobCJkP5SscsQ0UJNoWjJQKuyl2ZyytV0,23221
16
+ cloudnetpy/categorize/categorize.py,sha256=UZph73hVCU-UIxB2837oyLFKvTk8fdgLC-krgJDg8zk,23227
17
17
  cloudnetpy/categorize/classify.py,sha256=skA9K6Bxh9mFZ_fM4d78zt09BPDzfHLttXle6mFCMbw,8553
18
18
  cloudnetpy/categorize/containers.py,sha256=PIJwgQos3CxF9BG4hBNLTaZq252FTH0kdgagT31mFmc,5517
19
- cloudnetpy/categorize/disdrometer.py,sha256=XNL8kDtBAB12UmgRZ4ayxuVs8e3ghyLO0Hy5XpRgfMU,1966
19
+ cloudnetpy/categorize/disdrometer.py,sha256=_Hc7EhoxIIsAn7HCrgSB6aPMelaIW6c4lLeMf0NOnVI,1117
20
20
  cloudnetpy/categorize/droplet.py,sha256=wnMN9rHNSMZLXNXuYEd-RAS_8eAIIo2vkE7pp3DSTKs,8725
21
21
  cloudnetpy/categorize/falling.py,sha256=ZscFGFPFz_Nlc7PwjVwFDSVOzMGOuCDVAFj7pLvYctQ,4475
22
22
  cloudnetpy/categorize/freezing.py,sha256=gigqpb4qfeQSlKXkrPUwCbMnMsxl74thJWSRW2iHJOg,3796
23
23
  cloudnetpy/categorize/insects.py,sha256=bAqm4kFRtU16RPttsRLedofPd-yfbALNqz26jKlMNUE,5357
24
24
  cloudnetpy/categorize/itu.py,sha256=ffXK27guyRS4d66VWQ2h4UEGjUIhGjPKbFmj7kh698c,10304
25
- cloudnetpy/categorize/lidar.py,sha256=CQsDEeQYiuQCfCmJQWrqQvCfmciN1NPZ6uRdt89CZLY,2685
25
+ cloudnetpy/categorize/lidar.py,sha256=CkIbsMFHROYnhIc1e1ci61-POqeL8AOf6RCZicpNBVc,2452
26
26
  cloudnetpy/categorize/melting.py,sha256=vhc6zq3L4gp7oEPHMnQlT2m6YBE5-CS5gdTNA7gVHRg,6329
27
27
  cloudnetpy/categorize/model.py,sha256=iFakrXy3npbg4qUrpUGEBEdwBnmlWsMgogPCtfWl7sw,6805
28
- cloudnetpy/categorize/mwr.py,sha256=kzSivQuKrsqmFInDLlSM1R2wAG5j-tQebOi_1IwUW_I,1690
28
+ cloudnetpy/categorize/mwr.py,sha256=QKc6f_h0mCVjzSa4BrwTtVAPx0Tn1VJ4jqGmIBke5II,1710
29
29
  cloudnetpy/categorize/radar.py,sha256=2mTDa9BLxQeaORm-YPQ1lJyjAKew6NYzjtUvjpIvBYU,16044
30
30
  cloudnetpy/categorize/attenuations/__init__.py,sha256=kIyQEZ6VVO6jJOAndrt7jNU15pm0Cavh5GnDjFmIG1M,1040
31
31
  cloudnetpy/categorize/attenuations/gas_attenuation.py,sha256=emr-RCxQT0i2N8k6eBNhRsmsCBPHJzQsWJfjC4fVSTo,975
@@ -56,10 +56,10 @@ cloudnetpy/instruments/rpg.py,sha256=R1rUdeSADvB1IMkGOF1S0rUEJDGEI_19SPrmErZpn5M
56
56
  cloudnetpy/instruments/rpg_reader.py,sha256=NaOtTxXx20PozNTj1xNvmbsEsAxuplFXRzBiM1_-Zg4,11651
57
57
  cloudnetpy/instruments/toa5.py,sha256=CfmmBMv5iMGaWHIGBK01Rw24cuXC1R1RMNTXkmsm340,1760
58
58
  cloudnetpy/instruments/vaisala.py,sha256=tu7aljkMKep0uCWz-Sd-GuBXF_Yy421a4nHy0ffpMoc,4725
59
- cloudnetpy/instruments/weather_station.py,sha256=FuaGILEkd4MxXMpLrNGXNUjuuTkMIBf-J7y9oepIsdM,27586
59
+ cloudnetpy/instruments/weather_station.py,sha256=KD-pGpEEbeyma74DdNPd24PFxFCdZc1UMLE0Hm2PLO0,28509
60
60
  cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
61
61
  cloudnetpy/instruments/disdrometer/common.py,sha256=WCPRCfAlElUzZpllOSjjWrLG2jgkiRIy0rWz_omFoJQ,10815
62
- cloudnetpy/instruments/disdrometer/parsivel.py,sha256=1HIA52f1nGOvSd4SSTr2y3-JT3eKZWwdbMnIMRVvQ_U,25811
62
+ cloudnetpy/instruments/disdrometer/parsivel.py,sha256=OZTLZgSOMfPF5cxY-ICSb0gvyEMm_3JspmRYYvb9hCo,25837
63
63
  cloudnetpy/instruments/disdrometer/thies.py,sha256=7gPYFzpa58ot6pTblhEnY5eRw5yrue42XwyacHQm14k,11205
64
64
  cloudnetpy/model_evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
65
  cloudnetpy/model_evaluation/file_handler.py,sha256=yAbJ3yOqufQGV3rahwOm9-k1swEDDq8V8n-zaNVaN54,6473
@@ -117,10 +117,10 @@ cloudnetpy/products/lwc.py,sha256=xsNiiG6dGKIkWaFk0xWTabc1bZ4ULf6SqcqHs7itAUk,19
117
117
  cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe55y9ob58,16637951
118
118
  cloudnetpy/products/mwr_tools.py,sha256=MMWnp68U7bv157-CPB2VeTQvaR6zl7sexbBT_kJ_pn8,6734
119
119
  cloudnetpy/products/product_tools.py,sha256=eyqIw_0KhlpmmYQE69RpGdRIAOW7JVPlEgkTBp2kdps,11302
120
- cloudnetpy-1.83.0.dist-info/licenses/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
120
+ cloudnetpy-1.84.0.dist-info/licenses/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
121
121
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
122
- cloudnetpy-1.83.0.dist-info/METADATA,sha256=wDkaRhm_pjpqqiX-6MteJV6IvZeKpZ8XiqaxCehqnV4,5836
123
- cloudnetpy-1.83.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
124
- cloudnetpy-1.83.0.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
125
- cloudnetpy-1.83.0.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
126
- cloudnetpy-1.83.0.dist-info/RECORD,,
122
+ cloudnetpy-1.84.0.dist-info/METADATA,sha256=b1T8fzF9ooTKaIjpb03WolZZKzdvlBxNP8IyO38aD7U,5836
123
+ cloudnetpy-1.84.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
124
+ cloudnetpy-1.84.0.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
125
+ cloudnetpy-1.84.0.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
126
+ cloudnetpy-1.84.0.dist-info/RECORD,,