cloudnetpy 1.80.1__py3-none-any.whl → 1.80.3__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.
- cloudnetpy/categorize/categorize.py +5 -4
- cloudnetpy/instruments/radiometrics.py +24 -13
- cloudnetpy/instruments/weather_station.py +70 -18
- cloudnetpy/version.py +1 -1
- {cloudnetpy-1.80.1.dist-info → cloudnetpy-1.80.3.dist-info}/METADATA +1 -1
- {cloudnetpy-1.80.1.dist-info → cloudnetpy-1.80.3.dist-info}/RECORD +10 -10
- {cloudnetpy-1.80.1.dist-info → cloudnetpy-1.80.3.dist-info}/WHEEL +0 -0
- {cloudnetpy-1.80.1.dist-info → cloudnetpy-1.80.3.dist-info}/entry_points.txt +0 -0
- {cloudnetpy-1.80.1.dist-info → cloudnetpy-1.80.3.dist-info}/licenses/LICENSE +0 -0
- {cloudnetpy-1.80.1.dist-info → cloudnetpy-1.80.3.dist-info}/top_level.txt +0 -0
@@ -145,10 +145,11 @@ def generate_categorize(
|
|
145
145
|
return utils.time_grid(), data.radar.height
|
146
146
|
|
147
147
|
def _close_all() -> None:
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
obj
|
148
|
+
if "data" in locals():
|
149
|
+
for field in fields(data):
|
150
|
+
obj = getattr(data, field.name)
|
151
|
+
if isinstance(obj, DataSource):
|
152
|
+
obj.close()
|
152
153
|
|
153
154
|
try:
|
154
155
|
radar = Radar(input_files["radar"])
|
@@ -11,6 +11,7 @@ from pathlib import Path
|
|
11
11
|
from typing import Any, NamedTuple
|
12
12
|
|
13
13
|
import numpy as np
|
14
|
+
from numpy import ma
|
14
15
|
|
15
16
|
from cloudnetpy import output, utils
|
16
17
|
from cloudnetpy.cloudnetarray import CloudnetArray
|
@@ -122,12 +123,15 @@ class RadiometricsMP:
|
|
122
123
|
logging.info("Skipping unknown record type %d", record_type)
|
123
124
|
unknown_record_types.add(record_type)
|
124
125
|
continue
|
126
|
+
|
127
|
+
row_trimmed = [value for value in row if value != ""]
|
128
|
+
|
125
129
|
record = Record(
|
126
130
|
row_number=int(row[0]),
|
127
131
|
timestamp=_parse_datetime(row[1]),
|
128
132
|
block_type=block_type,
|
129
133
|
block_index=block_index,
|
130
|
-
values=dict(zip(column_names,
|
134
|
+
values=dict(zip(column_names, row_trimmed[3:], strict=True)),
|
131
135
|
)
|
132
136
|
rows.append(record)
|
133
137
|
|
@@ -148,6 +152,15 @@ class RadiometricsMP:
|
|
148
152
|
ah_times = []
|
149
153
|
block_titles = {}
|
150
154
|
skip_procs = set()
|
155
|
+
|
156
|
+
def _parse_floats() -> list[float]:
|
157
|
+
return [
|
158
|
+
float(record.values[column])
|
159
|
+
if record.values[column].replace(".", "", 1).isdigit()
|
160
|
+
else math.nan
|
161
|
+
for column in self.ranges
|
162
|
+
]
|
163
|
+
|
151
164
|
for record in self.raw_data:
|
152
165
|
if record.block_type == 100:
|
153
166
|
block_type = int(record.values["Record Type"]) - 1
|
@@ -157,20 +170,18 @@ class RadiometricsMP:
|
|
157
170
|
# "LV2 Processor" values "Zenith" and "0.00:90.00" should be OK
|
158
171
|
# but "Angle20(N)" and similar should be skipped.
|
159
172
|
proc = record.values["LV2 Processor"]
|
160
|
-
if proc.startswith("Angle"):
|
173
|
+
if proc.startswith(("Angle", "Zenith26")):
|
161
174
|
skip_procs.add(proc)
|
162
175
|
continue
|
163
176
|
if title == "Temperature (K)":
|
164
177
|
temp_times.append(record.timestamp)
|
165
|
-
temps.append(
|
166
|
-
[float(record.values[column]) for column in self.ranges]
|
167
|
-
)
|
178
|
+
temps.append(_parse_floats())
|
168
179
|
elif title == "Relative Humidity (%)":
|
169
180
|
rh_times.append(record.timestamp)
|
170
|
-
rhs.append(
|
181
|
+
rhs.append(_parse_floats())
|
171
182
|
elif title == "Vapor Density (g/m^3)":
|
172
183
|
ah_times.append(record.timestamp)
|
173
|
-
ahs.append(
|
184
|
+
ahs.append(_parse_floats())
|
174
185
|
elif record.block_type == 10:
|
175
186
|
if record.block_index == 0:
|
176
187
|
lwp = record.values["Lqint(mm)"]
|
@@ -182,15 +193,13 @@ class RadiometricsMP:
|
|
182
193
|
irt_times.append(record.timestamp)
|
183
194
|
irts.append([float(irt)])
|
184
195
|
temp_times.append(record.timestamp)
|
185
|
-
temps.append(
|
186
|
-
[float(record.values[column]) for column in self.ranges]
|
187
|
-
)
|
196
|
+
temps.append(_parse_floats())
|
188
197
|
elif record.block_index == 1:
|
189
198
|
ah_times.append(record.timestamp)
|
190
|
-
ahs.append(
|
199
|
+
ahs.append(_parse_floats())
|
191
200
|
elif record.block_index == 2:
|
192
201
|
rh_times.append(record.timestamp)
|
193
|
-
rhs.append(
|
202
|
+
rhs.append(_parse_floats())
|
194
203
|
elif record.block_type == 200:
|
195
204
|
irt_times.append(record.timestamp)
|
196
205
|
irt = record.values["Tir(K)"]
|
@@ -204,6 +213,7 @@ class RadiometricsMP:
|
|
204
213
|
times.append(record.timestamp)
|
205
214
|
lwps.append(float(lwp))
|
206
215
|
iwvs.append(float(iwv))
|
216
|
+
|
207
217
|
self.data["time"] = np.array(times, dtype="datetime64[s]")
|
208
218
|
self.data["lwp"] = np.array(lwps) # mm => kg m-2
|
209
219
|
self.data["iwv"] = np.array(iwvs) * 10 # cm => kg m-2
|
@@ -346,7 +356,8 @@ class RadiometricsCombined:
|
|
346
356
|
if key in ("temperature", "relative_humidity", "absolute_humidity")
|
347
357
|
else None
|
348
358
|
)
|
349
|
-
|
359
|
+
array_masked = ma.masked_invalid(array) if np.isnan(array).any() else array
|
360
|
+
self.data[key] = CloudnetArray(array_masked, key, dimensions=dimensions)
|
350
361
|
|
351
362
|
def add_meta(self) -> None:
|
352
363
|
"""Adds some metadata."""
|
@@ -3,7 +3,7 @@ import datetime
|
|
3
3
|
import math
|
4
4
|
import re
|
5
5
|
from collections import defaultdict
|
6
|
-
from collections.abc import Iterable
|
6
|
+
from collections.abc import Iterable, Sequence
|
7
7
|
from os import PathLike
|
8
8
|
|
9
9
|
import numpy as np
|
@@ -21,11 +21,11 @@ from cloudnetpy.utils import datetime2decimal_hours
|
|
21
21
|
|
22
22
|
|
23
23
|
def ws2nc(
|
24
|
-
weather_station_file: str |
|
24
|
+
weather_station_file: str | PathLike | Sequence[str | PathLike],
|
25
25
|
output_file: str,
|
26
26
|
site_meta: dict,
|
27
27
|
uuid: str | None = None,
|
28
|
-
date: str | None = None,
|
28
|
+
date: str | datetime.date | None = None,
|
29
29
|
) -> str:
|
30
30
|
"""Converts weather station data into Cloudnet Level 1b netCDF file.
|
31
31
|
|
@@ -43,8 +43,10 @@ def ws2nc(
|
|
43
43
|
Raises:
|
44
44
|
ValidTimeStampError: No valid timestamps found.
|
45
45
|
"""
|
46
|
-
if
|
46
|
+
if isinstance(weather_station_file, str | PathLike):
|
47
47
|
weather_station_file = [weather_station_file]
|
48
|
+
if isinstance(date, str):
|
49
|
+
date = datetime.date.fromisoformat(date)
|
48
50
|
ws: WS
|
49
51
|
if site_meta["name"] == "Palaiseau":
|
50
52
|
ws = PalaiseauWS(weather_station_file, site_meta)
|
@@ -64,6 +66,8 @@ def ws2nc(
|
|
64
66
|
ws = LampedusaWS(weather_station_file, site_meta)
|
65
67
|
elif site_meta["name"] == "Limassol":
|
66
68
|
ws = LimassolWS(weather_station_file, site_meta)
|
69
|
+
elif site_meta["name"] == "L'Aquila":
|
70
|
+
ws = LAquilaWS(weather_station_file, site_meta)
|
67
71
|
else:
|
68
72
|
msg = "Unsupported site"
|
69
73
|
raise ValueError(msg)
|
@@ -98,8 +102,8 @@ class WS(CSVFile):
|
|
98
102
|
rainfall_amount = ma.cumsum(self.data["rainfall_rate"].data * resolution)
|
99
103
|
self.data["rainfall_amount"] = CloudnetArray(rainfall_amount, "rainfall_amount")
|
100
104
|
|
101
|
-
def screen_timestamps(self, date:
|
102
|
-
dates = np.array([
|
105
|
+
def screen_timestamps(self, date: datetime.date) -> None:
|
106
|
+
dates = np.array([d.date() for d in self._data["time"]])
|
103
107
|
valid_mask = dates == date
|
104
108
|
if not valid_mask.any():
|
105
109
|
raise ValidTimeStampError
|
@@ -139,7 +143,7 @@ class WS(CSVFile):
|
|
139
143
|
|
140
144
|
|
141
145
|
class PalaiseauWS(WS):
|
142
|
-
def __init__(self, filenames:
|
146
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
143
147
|
super().__init__(site_meta)
|
144
148
|
self.filenames = filenames
|
145
149
|
self._data = self._read_data()
|
@@ -170,8 +174,8 @@ class PalaiseauWS(WS):
|
|
170
174
|
decimal_hours = datetime2decimal_hours(self._data["time"])
|
171
175
|
self.data["time"] = CloudnetArray(decimal_hours, "time")
|
172
176
|
|
173
|
-
def screen_timestamps(self, date:
|
174
|
-
dates = [
|
177
|
+
def screen_timestamps(self, date: datetime.date) -> None:
|
178
|
+
dates = [d.date() for d in self._data["time"]]
|
175
179
|
valid_ind = [ind for ind, d in enumerate(dates) if d == date]
|
176
180
|
if not valid_ind:
|
177
181
|
raise ValidTimeStampError
|
@@ -228,7 +232,7 @@ class BucharestWS(PalaiseauWS):
|
|
228
232
|
|
229
233
|
|
230
234
|
class GranadaWS(WS):
|
231
|
-
def __init__(self, filenames:
|
235
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
232
236
|
if len(filenames) != 1:
|
233
237
|
raise ValueError
|
234
238
|
super().__init__(site_meta)
|
@@ -278,7 +282,7 @@ class GranadaWS(WS):
|
|
278
282
|
|
279
283
|
|
280
284
|
class KenttarovaWS(WS):
|
281
|
-
def __init__(self, filenames:
|
285
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
282
286
|
super().__init__(site_meta)
|
283
287
|
self.filenames = filenames
|
284
288
|
self._data = self._read_data()
|
@@ -334,7 +338,7 @@ class HyytialaWS(WS):
|
|
334
338
|
- BbRT/mm = Bucket content in real-time (Pluvio200) [mm].
|
335
339
|
"""
|
336
340
|
|
337
|
-
def __init__(self, filenames:
|
341
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
338
342
|
super().__init__(site_meta)
|
339
343
|
self.filename = filenames[0]
|
340
344
|
self._data = self._read_data()
|
@@ -395,7 +399,7 @@ class HyytialaWS(WS):
|
|
395
399
|
|
396
400
|
|
397
401
|
class GalatiWS(WS):
|
398
|
-
def __init__(self, filenames:
|
402
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
399
403
|
super().__init__(site_meta)
|
400
404
|
self.filename = filenames[0]
|
401
405
|
self._data = self._read_data()
|
@@ -450,7 +454,7 @@ class GalatiWS(WS):
|
|
450
454
|
|
451
455
|
|
452
456
|
class JuelichWS(WS):
|
453
|
-
def __init__(self, filenames:
|
457
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
454
458
|
super().__init__(site_meta)
|
455
459
|
self.filename = filenames[0]
|
456
460
|
self._data = self._read_data()
|
@@ -496,7 +500,7 @@ class JuelichWS(WS):
|
|
496
500
|
class LampedusaWS(WS):
|
497
501
|
"""Read Lampedusa weather station data in ICOS format."""
|
498
502
|
|
499
|
-
def __init__(self, filenames:
|
503
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
500
504
|
super().__init__(site_meta)
|
501
505
|
self.filename = filenames[0]
|
502
506
|
self._data = self._read_data()
|
@@ -549,7 +553,7 @@ class LampedusaWS(WS):
|
|
549
553
|
|
550
554
|
|
551
555
|
class LimassolWS(WS):
|
552
|
-
def __init__(self, filenames:
|
556
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
553
557
|
super().__init__(site_meta)
|
554
558
|
self.filenames = filenames
|
555
559
|
self._data = defaultdict(list)
|
@@ -562,8 +566,8 @@ class LimassolWS(WS):
|
|
562
566
|
decimal_hours = datetime2decimal_hours(self._data["time"])
|
563
567
|
self.data["time"] = CloudnetArray(decimal_hours, "time")
|
564
568
|
|
565
|
-
def screen_timestamps(self, date:
|
566
|
-
dates = [
|
569
|
+
def screen_timestamps(self, date: datetime.date) -> None:
|
570
|
+
dates = [d.date() for d in self._data["time"]]
|
567
571
|
valid_ind = [ind for ind, d in enumerate(dates) if d == date]
|
568
572
|
if not valid_ind:
|
569
573
|
raise ValidTimeStampError
|
@@ -646,3 +650,51 @@ def _parse_sirta(filename: str | PathLike):
|
|
646
650
|
parsed = float(value)
|
647
651
|
output[column].append(parsed)
|
648
652
|
return output
|
653
|
+
|
654
|
+
|
655
|
+
class LAquilaWS(WS):
|
656
|
+
def __init__(self, filenames: Sequence[str | PathLike], site_meta: dict):
|
657
|
+
super().__init__(site_meta)
|
658
|
+
self.filenames = filenames
|
659
|
+
self._data = self._read_data()
|
660
|
+
|
661
|
+
def _read_data(self) -> dict:
|
662
|
+
data: dict[str, list] = {
|
663
|
+
key: []
|
664
|
+
for key in [
|
665
|
+
"time",
|
666
|
+
"air_temperature",
|
667
|
+
"air_pressure",
|
668
|
+
"relative_humidity",
|
669
|
+
"rainfall_rate",
|
670
|
+
"wind_speed",
|
671
|
+
"wind_direction",
|
672
|
+
]
|
673
|
+
}
|
674
|
+
for filename in self.filenames:
|
675
|
+
with open(filename) as f:
|
676
|
+
for row in f:
|
677
|
+
if row.startswith("#"):
|
678
|
+
continue
|
679
|
+
columns = row.split(",")
|
680
|
+
if len(columns) != 7:
|
681
|
+
continue
|
682
|
+
timestamp = datetime.datetime.strptime(
|
683
|
+
columns[0], "%Y-%m-%dT%H:%M:%SZ"
|
684
|
+
).replace(tzinfo=datetime.timezone.utc)
|
685
|
+
data["time"].append(timestamp)
|
686
|
+
data["air_temperature"].append(self._parse_value(columns[1]))
|
687
|
+
data["air_pressure"].append(self._parse_value(columns[2]))
|
688
|
+
data["relative_humidity"].append(self._parse_value(columns[3]))
|
689
|
+
data["rainfall_rate"].append(self._parse_value(columns[4]))
|
690
|
+
data["wind_speed"].append(self._parse_value(columns[5]))
|
691
|
+
data["wind_direction"].append(self._parse_value(columns[6]))
|
692
|
+
output = self.format_data(data)
|
693
|
+
_, time_ind = np.unique(output["time"], return_index=True)
|
694
|
+
for key in output:
|
695
|
+
output[key] = output[key][time_ind]
|
696
|
+
return output
|
697
|
+
|
698
|
+
def _parse_value(self, value: str) -> float:
|
699
|
+
value = value.strip()
|
700
|
+
return float(value) if value else math.nan
|
cloudnetpy/version.py
CHANGED
@@ -9,11 +9,11 @@ cloudnetpy/metadata.py,sha256=lO7BCbVAzFoH3Nq-VuezYX0f7MnbG1Zp11g5GSiuQwM,6189
|
|
9
9
|
cloudnetpy/output.py,sha256=gupxt4f_-eUrFsWMto8tnknoV-p9QauC9L6CJAqBILU,15988
|
10
10
|
cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
cloudnetpy/utils.py,sha256=WczDeGN408XSgGeaRLXFmlLjgAS67lK1osV0YEuKmwo,32027
|
12
|
-
cloudnetpy/version.py,sha256=
|
12
|
+
cloudnetpy/version.py,sha256=BW7NnO7naEy7O4jbwWQGYbmOwUJPOQWGf7cSaGqVr7g,72
|
13
13
|
cloudnetpy/categorize/__init__.py,sha256=s-SJaysvVpVVo5kidiruWQO6p3gv2TXwY1wEHYO5D6I,44
|
14
14
|
cloudnetpy/categorize/atmos_utils.py,sha256=RcmbKxm2COkE7WEya0mK3yX5rzUbrewRVh3ekm01RtM,10598
|
15
15
|
cloudnetpy/categorize/attenuation.py,sha256=Y_-fzmQTltWTqIZTulJhovC7a6ifpMcaAazDJcnMIOc,990
|
16
|
-
cloudnetpy/categorize/categorize.py,sha256=
|
16
|
+
cloudnetpy/categorize/categorize.py,sha256=E3WAG79UGRLsDK3ZfaRfk7Vedht4OMxSgjHOPVBqrS4,20824
|
17
17
|
cloudnetpy/categorize/classify.py,sha256=qovHgHsMku5kpl3cJxKteNBsG8GAkfI3Zo8QhJwZSFQ,8512
|
18
18
|
cloudnetpy/categorize/containers.py,sha256=9nAmI1OnR_uANyTZS1cD4do6NrC90EqliEMVrFnQY24,5398
|
19
19
|
cloudnetpy/categorize/disdrometer.py,sha256=sRSt2B932lrrkvycKoSaKEIaDVfq9Z7uU-4iHRr-fC0,1893
|
@@ -50,13 +50,13 @@ cloudnetpy/instruments/mrr.py,sha256=eeAzCp3CiHGauywjwvMUAFwZ4vBOZMcd3IlF8KsrLQo
|
|
50
50
|
cloudnetpy/instruments/nc_lidar.py,sha256=5gQG9PApnNPrHmS9_zanl8HEYIQuGRpbnzC3wfTcOyQ,1705
|
51
51
|
cloudnetpy/instruments/nc_radar.py,sha256=HlaZeH5939R86ukF8K-P4Kfzb5-CpLB15LU2u94C5eI,7330
|
52
52
|
cloudnetpy/instruments/pollyxt.py,sha256=U3g-ttmcs02LuLwVOydP3GjeNcmDyoYQroB-leIGdHY,10060
|
53
|
-
cloudnetpy/instruments/radiometrics.py,sha256=
|
53
|
+
cloudnetpy/instruments/radiometrics.py,sha256=qCiBTlp1H30DZTxKDN5Xn_4d-JkTNavpVIiUvpJkiMM,15617
|
54
54
|
cloudnetpy/instruments/rain_e_h3.py,sha256=JEg4Ko7ZdfjAUJwJ1BWdTkm4K7r3s8WKrPb-HidTqpg,5336
|
55
55
|
cloudnetpy/instruments/rpg.py,sha256=m3-xLJ-w2T7Ip7jBveWsGrts4tmNvdc-Lb4HebvHQjQ,17319
|
56
56
|
cloudnetpy/instruments/rpg_reader.py,sha256=ThztFuVrWxhmWVAfZTfQDeUiKK1XMTbtv08IBe8GK98,11364
|
57
57
|
cloudnetpy/instruments/toa5.py,sha256=CfmmBMv5iMGaWHIGBK01Rw24cuXC1R1RMNTXkmsm340,1760
|
58
58
|
cloudnetpy/instruments/vaisala.py,sha256=W_yu_f92cOq8RiiqDLj7bswxu9UMS3TITPWzP5xPdvA,4615
|
59
|
-
cloudnetpy/instruments/weather_station.py,sha256=
|
59
|
+
cloudnetpy/instruments/weather_station.py,sha256=C41Fv4kU1ihm3EGWhry5ESe4shnKims8O6wCzz2L78U,26844
|
60
60
|
cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
|
61
61
|
cloudnetpy/instruments/disdrometer/common.py,sha256=g52iK2aNp3Z88kovUmGVpC54NZomPa9D871gzO0AmQ4,9267
|
62
62
|
cloudnetpy/instruments/disdrometer/parsivel.py,sha256=HJZrEysQkx9MiIVPDV25CYHpXi_SjgZlgO-otoaKK34,25640
|
@@ -117,10 +117,10 @@ cloudnetpy/products/lwc.py,sha256=sl6Al2tuH3KkCBrPbWTmuz3jlD5UQJ4D6qBsn1tt2CQ,18
|
|
117
117
|
cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe55y9ob58,16637951
|
118
118
|
cloudnetpy/products/mwr_tools.py,sha256=8HPZpQMTojKZP1JS1S83IE0sxmbDE9bxlaWoqmGnUZE,6199
|
119
119
|
cloudnetpy/products/product_tools.py,sha256=uu4l6reuGbPcW3TgttbaSrqIKbyYGhBVTdnC7opKvmg,11101
|
120
|
-
cloudnetpy-1.80.
|
120
|
+
cloudnetpy-1.80.3.dist-info/licenses/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
|
121
121
|
docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
|
122
|
-
cloudnetpy-1.80.
|
123
|
-
cloudnetpy-1.80.
|
124
|
-
cloudnetpy-1.80.
|
125
|
-
cloudnetpy-1.80.
|
126
|
-
cloudnetpy-1.80.
|
122
|
+
cloudnetpy-1.80.3.dist-info/METADATA,sha256=N9oYLtyR_xAnhl0Q0pp1d91XHsfb6MPULyqg2_NtBlQ,5803
|
123
|
+
cloudnetpy-1.80.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
124
|
+
cloudnetpy-1.80.3.dist-info/entry_points.txt,sha256=HhY7LwCFk4qFgDlXx_Fy983ZTd831WlhtdPIzV-Y3dY,51
|
125
|
+
cloudnetpy-1.80.3.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
|
126
|
+
cloudnetpy-1.80.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|