cloudnetpy 1.61.11__py3-none-any.whl → 1.61.13__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/instruments/weather_station.py +131 -96
- cloudnetpy/plotting/plotting.py +24 -10
- cloudnetpy/version.py +1 -1
- {cloudnetpy-1.61.11.dist-info → cloudnetpy-1.61.13.dist-info}/METADATA +1 -1
- {cloudnetpy-1.61.11.dist-info → cloudnetpy-1.61.13.dist-info}/RECORD +8 -8
- {cloudnetpy-1.61.11.dist-info → cloudnetpy-1.61.13.dist-info}/LICENSE +0 -0
- {cloudnetpy-1.61.11.dist-info → cloudnetpy-1.61.13.dist-info}/WHEEL +0 -0
- {cloudnetpy-1.61.11.dist-info → cloudnetpy-1.61.13.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,7 @@ from numpy import ma
|
|
8
8
|
from cloudnetpy import output
|
9
9
|
from cloudnetpy.categorize import atmos_utils
|
10
10
|
from cloudnetpy.cloudnetarray import CloudnetArray
|
11
|
-
from cloudnetpy.constants import SEC_IN_HOUR
|
11
|
+
from cloudnetpy.constants import MM_H_TO_M_S, SEC_IN_HOUR
|
12
12
|
from cloudnetpy.exceptions import ValidTimeStampError, WeatherStationDataError
|
13
13
|
from cloudnetpy.instruments import instruments
|
14
14
|
from cloudnetpy.instruments.cloudnet_instrument import CloudnetInstrument
|
@@ -51,6 +51,8 @@ def ws2nc(
|
|
51
51
|
ws = GranadaWS(weather_station_file, site_meta)
|
52
52
|
elif site_meta["name"] == "Kenttärova":
|
53
53
|
ws = KenttarovaWS(weather_station_file, site_meta)
|
54
|
+
elif site_meta["name"] == "Hyytiälä":
|
55
|
+
ws = HyytialaWS(weather_station_file, site_meta)
|
54
56
|
else:
|
55
57
|
msg = "Unsupported site"
|
56
58
|
raise ValueError(msg) # noqa: TRY301
|
@@ -60,7 +62,10 @@ def ws2nc(
|
|
60
62
|
ws.add_date()
|
61
63
|
ws.add_site_geolocation()
|
62
64
|
ws.add_data()
|
63
|
-
ws.
|
65
|
+
ws.convert_temperature_and_humidity()
|
66
|
+
ws.convert_pressure()
|
67
|
+
ws.convert_rainfall_rate()
|
68
|
+
ws.convert_rainfall_amount()
|
64
69
|
ws.calculate_rainfall_amount()
|
65
70
|
attributes = output.add_time_attribute(ATTRIBUTES, ws.date)
|
66
71
|
output.update_attributes(ws.data, attributes)
|
@@ -70,22 +75,24 @@ def ws2nc(
|
|
70
75
|
|
71
76
|
|
72
77
|
class WS(CloudnetInstrument):
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
pass
|
78
|
+
def __init__(self):
|
79
|
+
super().__init__()
|
80
|
+
self._data: dict
|
77
81
|
|
78
|
-
|
79
|
-
pass
|
82
|
+
date: list[str]
|
80
83
|
|
81
84
|
def add_date(self) -> None:
|
82
|
-
|
85
|
+
first_date = self._data["time"][0].date()
|
86
|
+
self.date = [
|
87
|
+
str(first_date.year),
|
88
|
+
str(first_date.month).zfill(2),
|
89
|
+
str(first_date.day).zfill(2),
|
90
|
+
]
|
83
91
|
|
84
92
|
def add_data(self) -> None:
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
pass
|
93
|
+
for key, value in self._data.items():
|
94
|
+
parsed = datetime2decimal_hours(value) if key == "time" else ma.array(value)
|
95
|
+
self.data[key] = CloudnetArray(parsed, key)
|
89
96
|
|
90
97
|
def calculate_rainfall_amount(self) -> None:
|
91
98
|
if "rainfall_amount" in self.data:
|
@@ -94,6 +101,34 @@ class WS(CloudnetInstrument):
|
|
94
101
|
rainfall_amount = ma.cumsum(self.data["rainfall_rate"].data * resolution)
|
95
102
|
self.data["rainfall_amount"] = CloudnetArray(rainfall_amount, "rainfall_amount")
|
96
103
|
|
104
|
+
def screen_timestamps(self, date: str) -> None:
|
105
|
+
dates = [str(d.date()) for d in self._data["time"]]
|
106
|
+
valid_ind = [ind for ind, d in enumerate(dates) if d == date]
|
107
|
+
if not valid_ind:
|
108
|
+
raise ValidTimeStampError
|
109
|
+
for key in self._data:
|
110
|
+
self._data[key] = [
|
111
|
+
x for ind, x in enumerate(self._data[key]) if ind in valid_ind
|
112
|
+
]
|
113
|
+
|
114
|
+
def convert_temperature_and_humidity(self) -> None:
|
115
|
+
temperature_kelvins = atmos_utils.c2k(self.data["air_temperature"][:])
|
116
|
+
self.data["air_temperature"].data = temperature_kelvins
|
117
|
+
self.data["relative_humidity"].data = self.data["relative_humidity"][:] / 100
|
118
|
+
|
119
|
+
def convert_rainfall_rate(self) -> None:
|
120
|
+
rainfall_rate = self.data["rainfall_rate"][:]
|
121
|
+
self.data["rainfall_rate"].data = rainfall_rate / 60 / 1000 # mm/min -> m/s
|
122
|
+
|
123
|
+
def convert_pressure(self) -> None:
|
124
|
+
self.data["air_pressure"].data = self.data["air_pressure"][:] * 100 # hPa to Pa
|
125
|
+
|
126
|
+
def convert_time(self) -> None:
|
127
|
+
pass
|
128
|
+
|
129
|
+
def convert_rainfall_amount(self) -> None:
|
130
|
+
pass
|
131
|
+
|
97
132
|
|
98
133
|
class PalaiseauWS(WS):
|
99
134
|
def __init__(self, filenames: list[str], site_meta: dict):
|
@@ -141,14 +176,14 @@ class PalaiseauWS(WS):
|
|
141
176
|
for title, identifier in zip(column_titles, expected_identifiers, strict=True):
|
142
177
|
if identifier not in title:
|
143
178
|
raise ValueError(error_msg)
|
144
|
-
return {"
|
179
|
+
return {"time": timestamps, "values": values}
|
145
180
|
|
146
181
|
def convert_time(self) -> None:
|
147
|
-
decimal_hours = datetime2decimal_hours(self._data["
|
182
|
+
decimal_hours = datetime2decimal_hours(self._data["time"])
|
148
183
|
self.data["time"] = CloudnetArray(decimal_hours, "time")
|
149
184
|
|
150
185
|
def screen_timestamps(self, date: str) -> None:
|
151
|
-
dates = [str(d.date()) for d in self._data["
|
186
|
+
dates = [str(d.date()) for d in self._data["time"]]
|
152
187
|
valid_ind = [ind for ind, d in enumerate(dates) if d == date]
|
153
188
|
if not valid_ind:
|
154
189
|
raise ValidTimeStampError
|
@@ -157,14 +192,6 @@ class PalaiseauWS(WS):
|
|
157
192
|
x for ind, x in enumerate(self._data[key]) if ind in valid_ind
|
158
193
|
]
|
159
194
|
|
160
|
-
def add_date(self) -> None:
|
161
|
-
first_date = self._data["timestamps"][0].date()
|
162
|
-
self.date = [
|
163
|
-
str(first_date.year),
|
164
|
-
str(first_date.month).zfill(2),
|
165
|
-
str(first_date.day).zfill(2),
|
166
|
-
]
|
167
|
-
|
168
195
|
def add_data(self) -> None:
|
169
196
|
keys = (
|
170
197
|
"wind_speed",
|
@@ -180,13 +207,7 @@ class PalaiseauWS(WS):
|
|
180
207
|
array_masked = ma.masked_invalid(array)
|
181
208
|
self.data[key] = CloudnetArray(array_masked, key)
|
182
209
|
|
183
|
-
def
|
184
|
-
temperature_kelvins = atmos_utils.c2k(self.data["air_temperature"][:])
|
185
|
-
self.data["air_temperature"].data = temperature_kelvins
|
186
|
-
self.data["relative_humidity"].data = self.data["relative_humidity"][:] / 100
|
187
|
-
self.data["air_pressure"].data = self.data["air_pressure"][:] * 100 # hPa -> Pa
|
188
|
-
rainfall_rate = self.data["rainfall_rate"][:]
|
189
|
-
self.data["rainfall_rate"].data = rainfall_rate / 60 / 1000 # mm/min -> m/s
|
210
|
+
def convert_rainfall_amount(self) -> None:
|
190
211
|
self.data["rainfall_amount"].data = (
|
191
212
|
self.data["rainfall_amount"][:] / 1000
|
192
213
|
) # mm -> m
|
@@ -240,40 +261,6 @@ class GranadaWS(WS):
|
|
240
261
|
data[keymap[key]].append(parsed)
|
241
262
|
return data
|
242
263
|
|
243
|
-
def convert_time(self) -> None:
|
244
|
-
pass
|
245
|
-
|
246
|
-
def screen_timestamps(self, date: str) -> None:
|
247
|
-
dates = [str(d.date()) for d in self._data["time"]]
|
248
|
-
valid_ind = [ind for ind, d in enumerate(dates) if d == date]
|
249
|
-
if not valid_ind:
|
250
|
-
raise ValidTimeStampError
|
251
|
-
for key in self._data:
|
252
|
-
self._data[key] = [
|
253
|
-
x for ind, x in enumerate(self._data[key]) if ind in valid_ind
|
254
|
-
]
|
255
|
-
|
256
|
-
def add_date(self) -> None:
|
257
|
-
first_date = self._data["time"][0].date()
|
258
|
-
self.date = [
|
259
|
-
str(first_date.year),
|
260
|
-
str(first_date.month).zfill(2),
|
261
|
-
str(first_date.day).zfill(2),
|
262
|
-
]
|
263
|
-
|
264
|
-
def add_data(self) -> None:
|
265
|
-
for key, value in self._data.items():
|
266
|
-
parsed = datetime2decimal_hours(value) if key == "time" else np.array(value)
|
267
|
-
self.data[key] = CloudnetArray(parsed, key)
|
268
|
-
|
269
|
-
def convert_units(self) -> None:
|
270
|
-
temperature_kelvins = atmos_utils.c2k(self.data["air_temperature"][:])
|
271
|
-
self.data["air_temperature"].data = temperature_kelvins
|
272
|
-
self.data["relative_humidity"].data = self.data["relative_humidity"][:] / 100
|
273
|
-
self.data["air_pressure"].data = self.data["air_pressure"][:] * 100 # hPa -> Pa
|
274
|
-
rainfall_rate = self.data["rainfall_rate"][:]
|
275
|
-
self.data["rainfall_rate"].data = rainfall_rate / 60 / 1000 # mm/min -> m/s
|
276
|
-
|
277
264
|
|
278
265
|
class KenttarovaWS(WS):
|
279
266
|
def __init__(self, filenames: list[str], site_meta: dict):
|
@@ -322,41 +309,89 @@ class KenttarovaWS(WS):
|
|
322
309
|
merged[key] = new_value
|
323
310
|
return merged
|
324
311
|
|
325
|
-
def
|
326
|
-
|
312
|
+
def convert_rainfall_rate(self) -> None:
|
313
|
+
# Rainfall rate is 10-minute averaged in mm h-1
|
314
|
+
rainfall_rate = self.data["rainfall_rate"][:]
|
315
|
+
self.data["rainfall_rate"].data = rainfall_rate * MM_H_TO_M_S / 10
|
327
316
|
|
328
|
-
def
|
329
|
-
|
330
|
-
|
331
|
-
if not valid_ind:
|
332
|
-
raise ValidTimeStampError
|
333
|
-
for key in self._data:
|
334
|
-
self._data[key] = [
|
335
|
-
x for ind, x in enumerate(self._data[key]) if ind in valid_ind
|
336
|
-
]
|
317
|
+
def convert_pressure(self) -> None:
|
318
|
+
# Magic number 10 to convert to realistic Pa
|
319
|
+
self.data["air_pressure"].data = self.data["air_pressure"][:] * 10
|
337
320
|
|
338
|
-
def add_date(self) -> None:
|
339
|
-
first_date = self._data["time"][0].date()
|
340
|
-
self.date = [
|
341
|
-
str(first_date.year),
|
342
|
-
str(first_date.month).zfill(2),
|
343
|
-
str(first_date.day).zfill(2),
|
344
|
-
]
|
345
321
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
322
|
+
class HyytialaWS(WS):
|
323
|
+
"""
|
324
|
+
Hyytiälä rain-gauge variables: a = Pluvio400 and b = Pluvio200.
|
325
|
+
E.g.
|
326
|
+
- AaRNRT/mm = amount of non-real-time rain total (Pluvio400) [mm]
|
327
|
+
- BbRT/mm = Bucket content in real-time (Pluvio200) [mm]
|
328
|
+
"""
|
350
329
|
|
351
|
-
def
|
352
|
-
|
353
|
-
self.
|
354
|
-
self.
|
355
|
-
self.
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
330
|
+
def __init__(self, filenames: list[str], site_meta: dict):
|
331
|
+
super().__init__()
|
332
|
+
self.filename = filenames[0]
|
333
|
+
self.site_meta = site_meta
|
334
|
+
self.instrument = instruments.GENERIC_WEATHER_STATION
|
335
|
+
self._data = self._read_data()
|
336
|
+
|
337
|
+
def _read_data(self) -> dict:
|
338
|
+
with open(self.filename, newline="") as f:
|
339
|
+
# Skip first two lines
|
340
|
+
for _ in range(2):
|
341
|
+
next(f)
|
342
|
+
# Read header
|
343
|
+
header_line = f.readline().strip()
|
344
|
+
fields = header_line[1:].strip().split()
|
345
|
+
reader = csv.DictReader(
|
346
|
+
f, delimiter=" ", skipinitialspace=True, fieldnames=fields
|
347
|
+
)
|
348
|
+
if reader.fieldnames is None:
|
349
|
+
raise ValueError
|
350
|
+
raw_data: dict = {key: [] for key in reader.fieldnames}
|
351
|
+
raw_data["time"] = []
|
352
|
+
# Read data
|
353
|
+
for row in reader:
|
354
|
+
for key, value in row.items():
|
355
|
+
if key:
|
356
|
+
parsed_value: float | datetime.datetime
|
357
|
+
if key == "y":
|
358
|
+
current_time = datetime.datetime(
|
359
|
+
int(value),
|
360
|
+
int(row["m"]),
|
361
|
+
int(row["d"]),
|
362
|
+
int(row["minute"]) // 60,
|
363
|
+
int(row["minute"]) % 60,
|
364
|
+
)
|
365
|
+
raw_data["time"].append(current_time)
|
366
|
+
else:
|
367
|
+
try:
|
368
|
+
parsed_value = float(value)
|
369
|
+
except (TypeError, ValueError):
|
370
|
+
parsed_value = math.nan
|
371
|
+
if parsed_value == -99.99:
|
372
|
+
parsed_value = math.nan
|
373
|
+
raw_data[key].append(parsed_value)
|
374
|
+
|
375
|
+
data = {
|
376
|
+
"time": raw_data["time"],
|
377
|
+
"air_temperature": raw_data["Ta/dsC"],
|
378
|
+
"relative_humidity": raw_data["RH/pcnt"],
|
379
|
+
"air_pressure": raw_data["Pa/kPa"],
|
380
|
+
"wind_speed": raw_data["WS/(m/s)"],
|
381
|
+
"wind_direction": raw_data["WD/ds"],
|
382
|
+
"rainfall_rate": raw_data["AaNRT/mm"],
|
383
|
+
}
|
384
|
+
for key, value in data.items():
|
385
|
+
new_value = np.array(value)
|
386
|
+
if key != "time":
|
387
|
+
new_value = ma.masked_where(np.isnan(new_value), new_value)
|
388
|
+
data[key] = new_value
|
389
|
+
return data
|
390
|
+
|
391
|
+
def convert_pressure(self) -> None:
|
392
|
+
self.data["air_pressure"].data = (
|
393
|
+
self.data["air_pressure"][:] * 1000
|
394
|
+
) # kPa to Pa
|
360
395
|
|
361
396
|
|
362
397
|
ATTRIBUTES = {
|
cloudnetpy/plotting/plotting.py
CHANGED
@@ -4,6 +4,7 @@ import re
|
|
4
4
|
import textwrap
|
5
5
|
from dataclasses import dataclass
|
6
6
|
from datetime import date
|
7
|
+
from typing import Any
|
7
8
|
|
8
9
|
import matplotlib.pyplot as plt
|
9
10
|
import netCDF4
|
@@ -356,7 +357,7 @@ class Plot:
|
|
356
357
|
raise ValueError(msg)
|
357
358
|
max_gap_fraction_hour = _get_max_gap_in_minutes(figure_data) / 60
|
358
359
|
|
359
|
-
if figure_data.file
|
360
|
+
if getattr(figure_data.file, "cloudnet_file_type", "") == "model":
|
360
361
|
time, data = screen_completely_masked_profiles(time, data)
|
361
362
|
|
362
363
|
gap_indices = np.where(np.diff(time) > max_gap_fraction_hour)[0]
|
@@ -491,15 +492,28 @@ class Plot2D(Plot):
|
|
491
492
|
smoothed_data = uniform_filter(self._data[valid_time_ind, :], sigma_units)
|
492
493
|
self._data[valid_time_ind, :] = smoothed_data
|
493
494
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
495
|
+
pcolor_kwargs = {
|
496
|
+
"cmap": plt.get_cmap(str(self._plot_meta.cmap)),
|
497
|
+
"vmin": vmin,
|
498
|
+
"vmax": vmax,
|
499
|
+
"zorder": _get_zorder("data"),
|
500
|
+
}
|
501
|
+
image: Any
|
502
|
+
if getattr(figure_data.file, "cloudnet_file_type", "") == "model":
|
503
|
+
image = self._ax.pcolor(
|
504
|
+
figure_data.time_including_gaps,
|
505
|
+
alt,
|
506
|
+
self._data.T,
|
507
|
+
**pcolor_kwargs,
|
508
|
+
shading="nearest",
|
509
|
+
)
|
510
|
+
else:
|
511
|
+
image = self._ax.pcolorfast(
|
512
|
+
figure_data.time_including_gaps,
|
513
|
+
alt,
|
514
|
+
self._data.T[:-1, :-1],
|
515
|
+
**pcolor_kwargs,
|
516
|
+
)
|
503
517
|
cbar = self._init_colorbar(image)
|
504
518
|
cbar.set_label(str(self._plot_meta.clabel), fontsize=13)
|
505
519
|
|
cloudnetpy/version.py
CHANGED
@@ -8,7 +8,7 @@ cloudnetpy/metadata.py,sha256=v_VDo2vbdTxB0zIsfP69IcrwSKiRlLpsGdq6JPI4CoA,5306
|
|
8
8
|
cloudnetpy/output.py,sha256=UzF0w51c6-QEBj-NfCJg5zTIKVzcmq1HyQb-3_qWTgk,14767
|
9
9
|
cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
10
|
cloudnetpy/utils.py,sha256=-8x7LQ6WDHxf2lDZfhG50WYe2iSVLQObnVXZG46JzKI,28468
|
11
|
-
cloudnetpy/version.py,sha256=
|
11
|
+
cloudnetpy/version.py,sha256=s1z4RwSs7fLnDJ-S01W99lgOij26tF-b_d0xSRnP25k,73
|
12
12
|
cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
|
13
13
|
cloudnetpy/categorize/atmos.py,sha256=fWW8ye_8HZASRAiYwURFKWzcGOYIA2RKeVxCq0lVOuM,12389
|
14
14
|
cloudnetpy/categorize/atmos_utils.py,sha256=wndpwJxc2-QnNTkV8tc8I11Vs_WkNz9sVMX1fuGgUC4,3777
|
@@ -47,7 +47,7 @@ cloudnetpy/instruments/rpg.py,sha256=yQpcKcgzRvVvkl6NhKvo4PUkv9nZ69_hzzPpS2Ei-Is
|
|
47
47
|
cloudnetpy/instruments/rpg_reader.py,sha256=LAdXL3TmD5QzQbqtPOcemZji_qkXwmw6a6F8NmF6Zg8,11355
|
48
48
|
cloudnetpy/instruments/toa5.py,sha256=1JnuYViD8c_tHJZ9lf4OU44iepEkXHsXOzDfVf_b0qc,1759
|
49
49
|
cloudnetpy/instruments/vaisala.py,sha256=ektdXoID2X_V9H5Zp1fgHTUBapFMSyPVEWW_aoR6DEY,14655
|
50
|
-
cloudnetpy/instruments/weather_station.py,sha256=
|
50
|
+
cloudnetpy/instruments/weather_station.py,sha256=WnU1z7JhgsAvqzUhYg1XeUkUBgvYRnt2LUWnea8IugM,15216
|
51
51
|
cloudnetpy/instruments/disdrometer/__init__.py,sha256=lyjwttWvFvuwYxEkusoAvgRcbBmglmOp5HJOpXUqLWo,93
|
52
52
|
cloudnetpy/instruments/disdrometer/common.py,sha256=g52iK2aNp3Z88kovUmGVpC54NZomPa9D871gzO0AmQ4,9267
|
53
53
|
cloudnetpy/instruments/disdrometer/parsivel.py,sha256=WiL-vCjw9Gmb5irvW3AXddsyprp8MGOfqcVAlfy0zpc,25521
|
@@ -94,7 +94,7 @@ cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V
|
|
94
94
|
cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
|
95
95
|
cloudnetpy/plotting/__init__.py,sha256=lg9Smn4BI0dVBgnDLC3JVJ4GmwoSnO-qoSd4ApvwV6Y,107
|
96
96
|
cloudnetpy/plotting/plot_meta.py,sha256=cLdCZrhbP-gaobS_zjcf8d2xVALzl7zh2qpttxCHyrg,15983
|
97
|
-
cloudnetpy/plotting/plotting.py,sha256=
|
97
|
+
cloudnetpy/plotting/plotting.py,sha256=t6Bljy63HrBkBBNl6VuESV1utIS9mxrIxrNwDFNurRs,32926
|
98
98
|
cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
|
99
99
|
cloudnetpy/products/classification.py,sha256=pzFQtgOKS7g_3LqiAY84EFUUste-VES7CJNgoq2Bs34,7914
|
100
100
|
cloudnetpy/products/der.py,sha256=XZMbqDQUq0E9iBU3Axr-NfUJfRAhjsaGlyxJ4tKyGcw,12444
|
@@ -108,8 +108,8 @@ cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe5
|
|
108
108
|
cloudnetpy/products/mwr_tools.py,sha256=RuzokxxqXlTGk7XAOrif_FDPUJdf0j_wJgNq-7a_nK8,4684
|
109
109
|
cloudnetpy/products/product_tools.py,sha256=rhx_Ru9FLlQqCNM-awoiHx18-Aq1eBwL9LiUaQoJs6k,10412
|
110
110
|
docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
|
111
|
-
cloudnetpy-1.61.
|
112
|
-
cloudnetpy-1.61.
|
113
|
-
cloudnetpy-1.61.
|
114
|
-
cloudnetpy-1.61.
|
115
|
-
cloudnetpy-1.61.
|
111
|
+
cloudnetpy-1.61.13.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
|
112
|
+
cloudnetpy-1.61.13.dist-info/METADATA,sha256=R09GyBfK_BYlnHuZyPPX8H7JXhkWNxFExGWTSP2h7D8,5785
|
113
|
+
cloudnetpy-1.61.13.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
114
|
+
cloudnetpy-1.61.13.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
|
115
|
+
cloudnetpy-1.61.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|