oafuncs 0.0.98.19__py3-none-any.whl → 0.0.98.21__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.
- oafuncs/_script/data_interp.py +25 -15
- oafuncs/_script/data_interp_geo.py +144 -75
- oafuncs/_script/netcdf_merge.py +51 -33
- oafuncs/_script/netcdf_write.py +333 -69
- oafuncs/_script/parallel.py +4 -1
- oafuncs/oa_cmap.py +2 -2
- oafuncs/oa_data.py +43 -3
- oafuncs/oa_down/hycom_3hourly.py +4 -20
- oafuncs/oa_draw.py +2 -2
- oafuncs/oa_nc.py +73 -6
- oafuncs/oa_tool.py +1 -1
- {oafuncs-0.0.98.19.dist-info → oafuncs-0.0.98.21.dist-info}/METADATA +1 -1
- {oafuncs-0.0.98.19.dist-info → oafuncs-0.0.98.21.dist-info}/RECORD +16 -16
- {oafuncs-0.0.98.19.dist-info → oafuncs-0.0.98.21.dist-info}/WHEEL +1 -1
- {oafuncs-0.0.98.19.dist-info → oafuncs-0.0.98.21.dist-info}/licenses/LICENSE.txt +0 -0
- {oafuncs-0.0.98.19.dist-info → oafuncs-0.0.98.21.dist-info}/top_level.txt +0 -0
oafuncs/oa_down/hycom_3hourly.py
CHANGED
@@ -1,18 +1,3 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
# coding=utf-8
|
3
|
-
"""
|
4
|
-
Author: Liu Kun && 16031215@qq.com
|
5
|
-
Date: 2025-04-07 10:51:09
|
6
|
-
LastEditors: Liu Kun && 16031215@qq.com
|
7
|
-
LastEditTime: 2025-04-07 10:51:09
|
8
|
-
FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_down\\hycom_3hourly copy.py
|
9
|
-
Description:
|
10
|
-
EditPlatform: vscode
|
11
|
-
ComputerInfo: XPS 15 9510
|
12
|
-
SystemInfo: Windows 11
|
13
|
-
Python Version: 3.12
|
14
|
-
"""
|
15
|
-
|
16
1
|
import asyncio
|
17
2
|
import datetime
|
18
3
|
import logging
|
@@ -23,7 +8,6 @@ import warnings
|
|
23
8
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
24
9
|
from pathlib import Path
|
25
10
|
from threading import Lock
|
26
|
-
from oafuncs.oa_tool import pbar
|
27
11
|
|
28
12
|
import httpx
|
29
13
|
import matplotlib.pyplot as plt
|
@@ -38,6 +22,7 @@ from oafuncs.oa_down.user_agent import get_ua
|
|
38
22
|
from oafuncs.oa_file import file_size
|
39
23
|
from oafuncs.oa_nc import check as check_nc
|
40
24
|
from oafuncs.oa_nc import modify as modify_nc
|
25
|
+
from oafuncs.oa_tool import pbar
|
41
26
|
|
42
27
|
logging.getLogger("httpx").setLevel(logging.WARNING) # 关闭 httpx 的 INFO 日志,只显示 WARNING 及以上
|
43
28
|
|
@@ -724,7 +709,6 @@ class _HycomDownloader:
|
|
724
709
|
logging.info(f"{file_name}: {percent}% ({downloaded / 1024:.1f} KB / {total / 1024:.1f} KB)")
|
725
710
|
last_percent = percent
|
726
711
|
|
727
|
-
|
728
712
|
elapsed = datetime.datetime.now() - start
|
729
713
|
# logging.info(f"File {file_name} downloaded, Time: {elapsed}")
|
730
714
|
logging.info(f"Saving {file_name} ...")
|
@@ -966,7 +950,7 @@ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_mi
|
|
966
950
|
print("Downloading a series of files...")
|
967
951
|
time_list = _get_time_list(ymdh_time_s, ymdh_time_e, interval_hour, "hour")
|
968
952
|
# with Progress() as progress:
|
969
|
-
|
953
|
+
# task = progress.add_task(f"[cyan]{bar_desc}", total=len(time_list))
|
970
954
|
if num_workers is None or num_workers <= 1:
|
971
955
|
for i, time_str in pbar(enumerate(time_list), description=f"{bar_desc}", total=len(time_list), next_line=True):
|
972
956
|
_prepare_url_to_download(var, lon_min, lon_max, lat_min, lat_max, time_str, None, depth, level, store_path, dataset_name, version_name, cover)
|
@@ -976,7 +960,7 @@ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_mi
|
|
976
960
|
futures = [executor.submit(_download_task, var, time_str, None, lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, cover) for time_str in time_list]
|
977
961
|
""" for feature in as_completed(futures):
|
978
962
|
_done_callback(feature, progress, task, len(time_list), counter_lock) """
|
979
|
-
for _ in pbar(as_completed(futures),description=f"{bar_desc}", total=len(futures),next_line=True):
|
963
|
+
for _ in pbar(as_completed(futures), description=f"{bar_desc}", total=len(futures), next_line=True):
|
980
964
|
pass
|
981
965
|
else:
|
982
966
|
print("[bold red]Please ensure the time_s is no more than time_e")
|
@@ -1174,7 +1158,7 @@ def download(
|
|
1174
1158
|
|
1175
1159
|
count_dict["total"] = count_dict["success"] + count_dict["fail"] + count_dict["skip"] + count_dict["no_data"]
|
1176
1160
|
print("[bold #ecdbfe]=" * mark_len)
|
1177
|
-
print(f"[bold #ff80ab]Total: {count_dict['total']}\nSuccess: {count_dict['success']}\nFail: {count_dict['fail']}\nSkip: {count_dict['skip']}\nNo data: {count_dict['no_data']}")
|
1161
|
+
print(f"[bold #ff80ab]Total : {count_dict['total']}\nSuccess: {count_dict['success']}\nFail : {count_dict['fail']}\nSkip : {count_dict['skip']}\nNo data: {count_dict['no_data']}")
|
1178
1162
|
print("[bold #ecdbfe]=" * mark_len)
|
1179
1163
|
if count_dict["fail"] > 0:
|
1180
1164
|
print("[bold #be5528]Please try again to download the failed data later.")
|
oafuncs/oa_draw.py
CHANGED
@@ -318,7 +318,7 @@ def add_gridlines(axes: plt.Axes, longitude_lines: list[float] = None, latitude_
|
|
318
318
|
if latitude_lines is not None:
|
319
319
|
gl.ylocator = mticker.FixedLocator(np.array(latitude_lines))
|
320
320
|
|
321
|
-
print("[green]Gridlines added successfully.[/green]")
|
321
|
+
# print("[green]Gridlines added successfully.[/green]")
|
322
322
|
return axes, gl
|
323
323
|
|
324
324
|
|
@@ -365,7 +365,7 @@ def add_cartopy(axes: plt.Axes, longitude_data: np.ndarray = None, latitude_data
|
|
365
365
|
lat_min, lat_max = np.nanmin(latitude_data), np.nanmax(latitude_data)
|
366
366
|
axes.set_extent([lon_min, lon_max, lat_min, lat_max], crs=map_projection)
|
367
367
|
|
368
|
-
print("[green]Cartopy features added successfully.[/green]")
|
368
|
+
# print("[green]Cartopy features added successfully.[/green]")
|
369
369
|
return axes
|
370
370
|
|
371
371
|
|
oafuncs/oa_nc.py
CHANGED
@@ -6,7 +6,8 @@ import numpy as np
|
|
6
6
|
import xarray as xr
|
7
7
|
from rich import print
|
8
8
|
|
9
|
-
__all__ = ["save", "merge", "modify", "rename", "check", "convert_longitude", "isel", "draw", "
|
9
|
+
__all__ = ["save", "merge", "modify", "rename", "check", "convert_longitude", "isel", "draw", "compress", "unscale"]
|
10
|
+
|
10
11
|
|
11
12
|
|
12
13
|
def save(
|
@@ -15,8 +16,10 @@ def save(
|
|
15
16
|
variable_name: Optional[str] = None,
|
16
17
|
coordinates: Optional[dict] = None,
|
17
18
|
write_mode: str = "w",
|
19
|
+
convert_dtype: str = "int32",
|
18
20
|
use_scale_offset: bool = True,
|
19
21
|
use_compression: bool = True,
|
22
|
+
preserve_mask_values: bool = True,
|
20
23
|
) -> None:
|
21
24
|
"""
|
22
25
|
Write data to a NetCDF file.
|
@@ -27,8 +30,10 @@ def save(
|
|
27
30
|
variable_name (Optional[str]): Variable name for the data.
|
28
31
|
coordinates (Optional[dict]): Coordinates, where keys are dimension names and values are coordinate data.
|
29
32
|
write_mode (str): Write mode, 'w' for write, 'a' for append. Default is 'w'.
|
33
|
+
convert_dtype (str): Data type to convert to. Default is 'int32'.
|
30
34
|
use_scale_offset (bool): Whether to use scale_factor and add_offset. Default is True.
|
31
35
|
use_compression (bool): Whether to use compression parameters. Default is True.
|
36
|
+
preserve_mask_values (bool): Whether to preserve mask values. Default is True.
|
32
37
|
|
33
38
|
Example:
|
34
39
|
>>> save(r'test.nc', data, 'u', {'time': np.linspace(0, 120, 100), 'lev': np.linspace(0, 120, 50)}, 'a')
|
@@ -38,7 +43,7 @@ def save(
|
|
38
43
|
"""
|
39
44
|
from ._script.netcdf_write import save_to_nc
|
40
45
|
|
41
|
-
save_to_nc(file_path, data, variable_name, coordinates, write_mode, use_scale_offset, use_compression)
|
46
|
+
save_to_nc(file_path, data, variable_name, coordinates, write_mode, convert_dtype,use_scale_offset, use_compression, preserve_mask_values)
|
42
47
|
print(f"[green]Data successfully saved to {file_path}[/green]")
|
43
48
|
|
44
49
|
|
@@ -278,7 +283,7 @@ def draw(
|
|
278
283
|
print("[red]No dataset or file provided.[/red]")
|
279
284
|
|
280
285
|
|
281
|
-
def
|
286
|
+
def compress(src_path, dst_path=None,convert_dtype='int16'):
|
282
287
|
"""
|
283
288
|
压缩 NetCDF 文件,使用 scale_factor/add_offset 压缩数据。
|
284
289
|
若 dst_path 省略,则自动生成新文件名,写出后删除原文件并将新文件改回原名。
|
@@ -289,7 +294,7 @@ def compress_netcdf(src_path, dst_path=None):
|
|
289
294
|
dst_path = src_path.replace(".nc", "_compress.nc")
|
290
295
|
|
291
296
|
ds = xr.open_dataset(src_path)
|
292
|
-
save(dst_path, ds)
|
297
|
+
save(dst_path, ds, convert_dtype=convert_dtype, use_scale_offset=True, use_compression=True)
|
293
298
|
ds.close()
|
294
299
|
|
295
300
|
if delete_orig:
|
@@ -298,26 +303,88 @@ def compress_netcdf(src_path, dst_path=None):
|
|
298
303
|
pass
|
299
304
|
|
300
305
|
|
301
|
-
def
|
306
|
+
def unscale(src_path, dst_path=None, compression_level=4):
|
302
307
|
"""解码 NetCDF 并移除 scale_factor/add_offset,写出真实值。
|
308
|
+
保留压缩功能,但不使用比例因子和偏移量,以控制文件大小。
|
303
309
|
若 dst_path 省略,则自动生成新文件名,写出后删除原文件并将新文件改回原名。
|
310
|
+
|
311
|
+
Args:
|
312
|
+
src_path: 源文件路径
|
313
|
+
dst_path: 目标文件路径,None则替换原文件
|
314
|
+
compression_level: 压缩级别(1-9),数值越大压缩比越高,速度越慢
|
304
315
|
"""
|
305
316
|
# 判断是否要替换原文件
|
306
317
|
delete_orig = dst_path is None
|
307
318
|
if delete_orig:
|
308
319
|
dst_path = src_path.replace(".nc", "_unpacked.nc")
|
309
320
|
|
321
|
+
# 打开原始文件,获取文件大小
|
322
|
+
orig_size = os.path.getsize(src_path) / (1024 * 1024) # MB
|
323
|
+
|
324
|
+
# 先以原始模式打开,查看哪些变量使用了scale_factor/add_offset
|
325
|
+
with xr.open_dataset(src_path, decode_cf=False) as ds_raw:
|
326
|
+
has_scaling = []
|
327
|
+
for var in ds_raw.data_vars:
|
328
|
+
if "scale_factor" in ds_raw[var].attrs or "add_offset" in ds_raw[var].attrs:
|
329
|
+
has_scaling.append(var)
|
330
|
+
|
331
|
+
print(f"[yellow]文件: {src_path} (原始大小: {orig_size:.2f} MB)[/yellow]")
|
332
|
+
if has_scaling:
|
333
|
+
print(f"[yellow]发现 {len(has_scaling)} 个变量使用了比例因子: {', '.join(has_scaling)}[/yellow]")
|
334
|
+
else:
|
335
|
+
print("[yellow]未发现任何变量使用比例因子,解包可能不必要[/yellow]")
|
336
|
+
|
337
|
+
# 解码模式打开
|
310
338
|
ds = xr.open_dataset(src_path, decode_cf=True)
|
339
|
+
encoding = {}
|
340
|
+
|
311
341
|
for var in ds.data_vars:
|
342
|
+
# 保存原始的_FillValue
|
343
|
+
fill_value = None
|
344
|
+
if "_FillValue" in ds[var].attrs:
|
345
|
+
fill_value = ds[var].attrs["_FillValue"]
|
346
|
+
elif "_FillValue" in ds[var].encoding:
|
347
|
+
fill_value = ds[var].encoding["_FillValue"]
|
348
|
+
|
349
|
+
# 清除scale_factor和add_offset属性
|
312
350
|
ds[var].attrs.pop("scale_factor", None)
|
313
351
|
ds[var].attrs.pop("add_offset", None)
|
314
352
|
ds[var].encoding.clear()
|
315
|
-
|
353
|
+
|
354
|
+
# 仅对数值型变量处理
|
355
|
+
if np.issubdtype(ds[var].dtype, np.number):
|
356
|
+
# 强制转换为float32,避免float64导致文件暴涨
|
357
|
+
if np.issubdtype(ds[var].dtype, np.floating) and ds[var].dtype != np.float32:
|
358
|
+
ds[var] = ds[var].astype(np.float32)
|
359
|
+
|
360
|
+
# 设置压缩参数,但不使用scale_factor/add_offset
|
361
|
+
encoding[var] = {"zlib": True, "complevel": compression_level, "dtype": ds[var].dtype}
|
362
|
+
# 恢复_FillValue
|
363
|
+
if fill_value is not None:
|
364
|
+
encoding[var]["_FillValue"] = fill_value
|
365
|
+
|
366
|
+
# 使用save函数保存,传入encoding确保只压缩不使用scale_factor
|
367
|
+
ds.to_netcdf(dst_path, encoding=encoding)
|
316
368
|
ds.close()
|
317
369
|
|
370
|
+
# 打印输出文件大小对比
|
371
|
+
if os.path.exists(dst_path):
|
372
|
+
new_size = os.path.getsize(dst_path) / (1024 * 1024) # MB
|
373
|
+
size_change = new_size - orig_size
|
374
|
+
change_percent = (size_change / orig_size) * 100
|
375
|
+
|
376
|
+
color = "green" if size_change <= 0 else "red"
|
377
|
+
print(f"[{color}]解包后文件大小: {new_size:.2f} MB ({change_percent:+.1f}%)[/{color}]")
|
378
|
+
|
379
|
+
if size_change > orig_size * 0.5 and new_size > 100: # 如果文件增长超过50%且大于100MB
|
380
|
+
print(f"[red]警告: 文件大小增长显著! 考虑增加压缩级别(当前:{compression_level})[/red]")
|
381
|
+
|
318
382
|
if delete_orig:
|
319
383
|
os.remove(src_path)
|
320
384
|
os.rename(dst_path, src_path)
|
385
|
+
print(f"[green]已替换原文件: {src_path}[/green]")
|
386
|
+
else:
|
387
|
+
print(f"[green]已保存到: {dst_path}[/green]")
|
321
388
|
|
322
389
|
|
323
390
|
if __name__ == "__main__":
|
oafuncs/oa_tool.py
CHANGED
@@ -135,7 +135,7 @@ def email(title: str = "Title", content: Optional[str] = None, send_to: str = "1
|
|
135
135
|
|
136
136
|
def pbar(
|
137
137
|
iterable: Iterable = range(100),
|
138
|
-
description: str = "Working
|
138
|
+
description: str = "Working",
|
139
139
|
total: Optional[float] = None,
|
140
140
|
completed: float = 0,
|
141
141
|
color: Any = "None",
|
@@ -1,29 +1,29 @@
|
|
1
1
|
oafuncs/__init__.py,sha256=T_-VtnWWllV3Q91twT5Yt2sUapeA051QbPNnBxmg9nw,1456
|
2
|
-
oafuncs/oa_cmap.py,sha256=
|
3
|
-
oafuncs/oa_data.py,sha256=
|
2
|
+
oafuncs/oa_cmap.py,sha256=NVKwEkmMUKXh9L1svx_WHqemLOx3evgX3_-UVDxc9ko,11498
|
3
|
+
oafuncs/oa_data.py,sha256=Aat9ktxxRGevaqQya3IJWfXeoEs-FCXGUcNE2pKnzfU,10931
|
4
4
|
oafuncs/oa_date.py,sha256=WhM6cyD4G3IeghjLTHhAMtlvJbA7kwQG2sHnxdTgyso,6303
|
5
|
-
oafuncs/oa_draw.py,sha256=
|
5
|
+
oafuncs/oa_draw.py,sha256=IaBGDx-EOxyMM2IuJ4zLZt6ruHHV5qFStPItmUOXoWk,17635
|
6
6
|
oafuncs/oa_file.py,sha256=j9gXJgPOJsliu4IOUc4bc-luW4yBvQyNCEmMyDVjUwQ,16404
|
7
7
|
oafuncs/oa_help.py,sha256=_4AZgRDq5Or0vauNvq5IDDHIBoBfdOQtzak-mG1wwAw,4537
|
8
|
-
oafuncs/oa_nc.py,sha256=
|
8
|
+
oafuncs/oa_nc.py,sha256=UUXnBg2cO5XiJ8w0jNqCZJg83FVKqxlEHxOJG5o08Z8,15201
|
9
9
|
oafuncs/oa_python.py,sha256=NkopwkYFGSEuVljnTBvXCl6o2CeyRNBqRXSsUl3euEE,5192
|
10
|
-
oafuncs/oa_tool.py,sha256=
|
10
|
+
oafuncs/oa_tool.py,sha256=QBjJh3pf54yXVuOmu97rW6Tsr6uNMyZ5KqZbR4VQFTc,8628
|
11
11
|
oafuncs/_data/hycom.png,sha256=MadKs6Gyj5n9-TOu7L4atQfTXtF9dvN9w-tdU9IfygI,10945710
|
12
12
|
oafuncs/_data/oafuncs.png,sha256=o3VD7wm-kwDea5E98JqxXl04_78cBX7VcdUt7uQXGiU,3679898
|
13
13
|
oafuncs/_script/cprogressbar.py,sha256=UIgGcLFs-6IgWlITuBLaQqrpt4OAK3Mst5RlCiNfZdQ,15772
|
14
|
-
oafuncs/_script/data_interp.py,sha256=
|
15
|
-
oafuncs/_script/data_interp_geo.py,sha256=
|
14
|
+
oafuncs/_script/data_interp.py,sha256=EiZbt6n5BEaRKcng88UgX7TFPhKE6TLVZniS01awXjg,5146
|
15
|
+
oafuncs/_script/data_interp_geo.py,sha256=ZRFb3fKRiYQViZNHd19eW20C9i38BsiIU8w0fG5mbqM,7789
|
16
16
|
oafuncs/_script/email.py,sha256=lL4HGKrr524-g0xLlgs-4u7x4-u7DtgNoD9AL8XJKj4,3058
|
17
|
-
oafuncs/_script/netcdf_merge.py,sha256=
|
17
|
+
oafuncs/_script/netcdf_merge.py,sha256=4mZLMcxBL4Rehi_eW2EX6vqbMJgZBOL4_ceaMzcuzio,5565
|
18
18
|
oafuncs/_script/netcdf_modify.py,sha256=sGRUYNhfGgf9JV70rnBzw3bzuTRSXzBTL_RMDnDPeLQ,4552
|
19
|
-
oafuncs/_script/netcdf_write.py,sha256=
|
20
|
-
oafuncs/_script/parallel.py,sha256=
|
19
|
+
oafuncs/_script/netcdf_write.py,sha256=GvyUyUhzMonzSp3y4pT8ZAfbQrsh5J3dLnmINYJKhuE,21422
|
20
|
+
oafuncs/_script/parallel.py,sha256=07-BJVHxXJNlrOrhrSGt7qCZiKWq6dBvNDBA1AANYnI,8861
|
21
21
|
oafuncs/_script/parallel_test.py,sha256=0GBqZOX7IaCOKF2t1y8N8YYu53GJ33OkfsWgpvZNqM4,372
|
22
22
|
oafuncs/_script/plot_dataset.py,sha256=zkSEnO_-biyagorwWXPoihts_cwuvripzEt-l9bHJ2E,13989
|
23
23
|
oafuncs/_script/replace_file_content.py,sha256=eCFZjnZcwyRvy6b4mmIfBna-kylSZTyJRfgXd6DdCjk,5982
|
24
24
|
oafuncs/oa_down/User_Agent-list.txt,sha256=pHaMlElMvZ8TG4vf4BqkZYKqe0JIGkr4kCN0lM1Y9FQ,514295
|
25
25
|
oafuncs/oa_down/__init__.py,sha256=kRX5eTUCbAiz3zTaQM1501paOYS_3fizDN4Pa0mtNUA,585
|
26
|
-
oafuncs/oa_down/hycom_3hourly.py,sha256=
|
26
|
+
oafuncs/oa_down/hycom_3hourly.py,sha256=R5fKfIcpNRuaQgPiov_hJRd8voWgAHVLWifAMzR6RQI,55075
|
27
27
|
oafuncs/oa_down/hycom_3hourly_proxy.py,sha256=1eaoJGI_m-7w4ZZ3n7NGxkZaeFdsm0d3U-hyw8RFNbc,54563
|
28
28
|
oafuncs/oa_down/idm.py,sha256=4z5IvgfTyIKEI1kOtqXZwN7Jnfjwp6qDBOIoVyOLp0I,1823
|
29
29
|
oafuncs/oa_down/literature.py,sha256=2bF9gSKQbzcci9LcKE81j8JEjIJwON7jbwQB3gDDA3E,11331
|
@@ -39,8 +39,8 @@ oafuncs/oa_sign/__init__.py,sha256=QKqTFrJDFK40C5uvk48GlRRbGFzO40rgkYwu6dYxatM,5
|
|
39
39
|
oafuncs/oa_sign/meteorological.py,sha256=8091SHo2L8kl4dCFmmSH5NGVHDku5i5lSiLEG5DLnOQ,6489
|
40
40
|
oafuncs/oa_sign/ocean.py,sha256=xrW-rWD7xBWsB5PuCyEwQ1Q_RDKq2KCLz-LOONHgldU,5932
|
41
41
|
oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw,5064
|
42
|
-
oafuncs-0.0.98.
|
43
|
-
oafuncs-0.0.98.
|
44
|
-
oafuncs-0.0.98.
|
45
|
-
oafuncs-0.0.98.
|
46
|
-
oafuncs-0.0.98.
|
42
|
+
oafuncs-0.0.98.21.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
|
43
|
+
oafuncs-0.0.98.21.dist-info/METADATA,sha256=Lk9y2XVdDKb9HB5PP_Pm-_aII0tnGmaladuGW1Y9otM,4273
|
44
|
+
oafuncs-0.0.98.21.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
|
45
|
+
oafuncs-0.0.98.21.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
|
46
|
+
oafuncs-0.0.98.21.dist-info/RECORD,,
|
File without changes
|
File without changes
|