oafuncs 0.0.97.10__py3-none-any.whl → 0.0.97.12__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.
@@ -0,0 +1,150 @@
1
+ # progressbar.py
2
+ import sys
3
+ import shutil
4
+ import time
5
+ import warnings
6
+ from typing import Iterable, Any, List, Union
7
+ import numpy as np
8
+
9
+ try:
10
+ from matplotlib.colors import LinearSegmentedColormap, to_rgb, to_hex
11
+ from matplotlib.cm import get_cmap
12
+ except ImportError:
13
+ raise ImportError("This module requires matplotlib. Install with: pip install matplotlib")
14
+
15
+
16
+ class ColorProgressBar:
17
+ def __init__(self, iterable: Iterable, prefix: str = "", color: Any = "cyan", cmap: Union[str, List[str]] = None, update_interval: float = 0.1, bar_length: int = None):
18
+ self.iterable = iterable
19
+ self.prefix = prefix
20
+ self.base_color = color
21
+ self.cmap = cmap
22
+ self.update_interval = update_interval
23
+ self.bar_length = bar_length
24
+
25
+ self._start_time = None
26
+ self._last_update = 0
27
+ self._count = len(iterable) if hasattr(iterable, "__len__") else None
28
+ self._file = sys.stdout
29
+ self._gradient_colors = self._generate_gradient() if cmap else None
30
+
31
+ def _generate_gradient(self) -> List[str]:
32
+ """生成渐变色列表(修复内置colormap支持)"""
33
+ try:
34
+ if isinstance(self.cmap, list):
35
+ cmap = LinearSegmentedColormap.from_list("custom_cmap", self.cmap)
36
+ else:
37
+ # 正确获取Matplotlib内置colormap
38
+ cmap = get_cmap(self.cmap)
39
+
40
+ return [to_hex(cmap(i)) for i in np.linspace(0, 1, self._count)]
41
+ except Exception as e:
42
+ warnings.warn(f"Colormap generation failed: {str(e)}")
43
+ return None
44
+
45
+ def _hex_to_ansi(self, hex_color: str) -> str:
46
+ """将颜色转换为ANSI真彩色代码"""
47
+ try:
48
+ rgb = [int(x * 255) for x in to_rgb(hex_color)]
49
+ return f"\033[38;2;{rgb[0]};{rgb[1]};{rgb[2]}m"
50
+ except ValueError as e:
51
+ warnings.warn(f"Invalid color value: {e}, falling back to cyan")
52
+ return "\033[96m"
53
+
54
+ def _resolve_color(self, index: int) -> str:
55
+ """解析当前应使用的颜色"""
56
+ if self._gradient_colors and index < len(self._gradient_colors):
57
+ try:
58
+ return self._hex_to_ansi(self._gradient_colors[index])
59
+ except IndexError:
60
+ pass
61
+
62
+ return self._process_color_value(self.base_color)
63
+
64
+ def _process_color_value(self, color: Any) -> str:
65
+ """处理颜色输入格式"""
66
+ preset_map = {
67
+ "red": "\033[91m",
68
+ "green": "\033[92m",
69
+ "yellow": "\033[93m",
70
+ "cyan": "\033[96m",
71
+ }
72
+
73
+ if color in preset_map:
74
+ return preset_map[color]
75
+
76
+ try:
77
+ hex_color = to_hex(color)
78
+ return self._hex_to_ansi(hex_color)
79
+ except (ValueError, TypeError) as e:
80
+ warnings.warn(f"Color parsing failed: {e}, using cyan")
81
+ return preset_map["cyan"]
82
+
83
+ def _format_bar(self, progress: float, width: int) -> str:
84
+ """格式化进度条显示"""
85
+ filled = "▊"
86
+ empty = " "
87
+ max_width = width - 50
88
+ filled_length = int(round(max_width * progress))
89
+ return filled * filled_length + empty * (max_width - filled_length)
90
+
91
+ def _calculate_speed(self, index: int, elapsed: float) -> tuple:
92
+ """计算速率和剩余时间"""
93
+ if index == 0 or elapsed < 1e-6:
94
+ return 0.0, 0.0
95
+
96
+ rate = index / elapsed
97
+ remaining = (self._count - index) / rate if self._count else 0
98
+ return rate, remaining
99
+
100
+ def __iter__(self):
101
+ self._start_time = time.time()
102
+ self._last_update = self._start_time
103
+ reset_code = "\033[0m"
104
+
105
+ for i, item in enumerate(self.iterable):
106
+ now = time.time()
107
+ elapsed = now - self._start_time
108
+ yield item
109
+
110
+ if (now - self._last_update) < self.update_interval and i + 1 != self._count:
111
+ continue
112
+
113
+ term_width = self.bar_length or shutil.get_terminal_size().columns
114
+ progress = (i + 1) / self._count if self._count else 0
115
+
116
+ current_color = self._resolve_color(i) if self._gradient_colors else self._resolve_color(0)
117
+
118
+ bar = self._format_bar(progress, term_width)
119
+ rate, remaining = self._calculate_speed(i + 1, elapsed)
120
+
121
+ count_info = f"{i + 1}/{self._count}" if self._count else str(i + 1)
122
+ percent = f"{progress:.1%}" if self._count else ""
123
+ rate_info = f"{rate:.1f}it/s" if rate else ""
124
+ time_info = f"ETA: {remaining:.1f}s" if self._count else f"Elapsed: {elapsed:.1f}s"
125
+
126
+ line = (f"\r{self.prefix}{current_color}[{bar}]{reset_code} {count_info} {percent} [{time_info} | {rate_info}]").ljust(term_width)
127
+
128
+ self._file.write(line)
129
+ self._file.flush()
130
+ self._last_update = now
131
+
132
+ self._file.write("\n")
133
+ self._file.flush()
134
+
135
+ @classmethod
136
+ def gradient_color(cls, colors: List[str], n: int) -> List[str]:
137
+ """生成渐变色列表"""
138
+ cmap = LinearSegmentedColormap.from_list("gradient", colors)
139
+ return [to_hex(cmap(i)) for i in np.linspace(0, 1, n)]
140
+
141
+
142
+ # 验证示例
143
+ if __name__ == "__main__":
144
+ # 正确使用内置colormap
145
+ for _ in ColorProgressBar(range(100), cmap="viridis", prefix="Viridis: "):
146
+ time.sleep(0.05)
147
+
148
+ # 使用自定义渐变色
149
+ for _ in ColorProgressBar(range(50), cmap=["#FF0000", "#0000FF"], prefix="Custom: "):
150
+ time.sleep(0.1)
oafuncs/oa_data.py CHANGED
@@ -22,8 +22,9 @@ import salem
22
22
  import xarray as xr
23
23
  from scipy.interpolate import griddata
24
24
  from scipy.interpolate import interp1d
25
+ from typing import Iterable
25
26
 
26
- __all__ = ["interp_along_dim", "interp_2d", "ensure_list", "mask_shapefile"]
27
+ __all__ = ["interp_along_dim", "interp_2d", "ensure_list", "mask_shapefile", "pbar"]
27
28
 
28
29
 
29
30
  def ensure_list(input_data):
@@ -254,6 +255,26 @@ def mask_shapefile(data: np.ndarray, lons: np.ndarray, lats: np.ndarray, shapefi
254
255
  return None
255
256
 
256
257
 
258
+ def pbar(iterable: Iterable, prefix: str = "", color: str = "cyan", cmap: str = None, **kwargs) -> Iterable:
259
+ """
260
+ 快速创建进度条的封装函数
261
+ :param iterable: 可迭代对象
262
+ :param prefix: 进度条前缀
263
+ :param color: 基础颜色
264
+ :param cmap: 渐变色名称
265
+ :param kwargs: 其他ColorProgressBar支持的参数
266
+
267
+ example:
268
+ from oafuncs.oa_data import pbar
269
+ from time import sleep
270
+ for i in pbar(range(100), prefix="Processing", color="green", cmap="viridis"):
271
+ sleep(0.1)
272
+ """
273
+ from ._script.cprogressbar import ColorProgressBar # 从progressbar.py导入类
274
+
275
+ return ColorProgressBar(iterable=iterable, prefix=prefix, color=color, cmap=cmap, **kwargs)
276
+
277
+
257
278
  if __name__ == "__main__":
258
279
  pass
259
280
  """ import time
@@ -900,7 +900,7 @@ def _get_submit_url_var(var, depth, level_num, lon_min, lon_max, lat_min, lat_ma
900
900
 
901
901
 
902
902
  def _prepare_url_to_download(var, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, download_time="2024083100", download_time_end=None, depth=None, level_num=None, store_path=None, dataset_name=None, version_name=None, check=False):
903
- print("[bold #ecdbfe]-" * 160)
903
+ print("[bold #ecdbfe]-" * mark_len)
904
904
  download_time = str(download_time)
905
905
  if download_time_end is not None:
906
906
  download_time_end = str(download_time_end)
@@ -1000,7 +1000,7 @@ def _done_callback(future, progress, task, total, counter_lock):
1000
1000
  progress.update(task, advance=1, description=f"[cyan]Downloading... {parallel_counter}/{total}")
1001
1001
 
1002
1002
 
1003
- def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level=None, store_path=None, dataset_name=None, version_name=None, num_workers=None, check=False, ftimes=1, download_interval=3):
1003
+ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level=None, store_path=None, dataset_name=None, version_name=None, num_workers=None, check=False, ftimes=1, interval_hour=3):
1004
1004
  """
1005
1005
  Description:
1006
1006
  Download the data of single time or a series of time
@@ -1032,7 +1032,7 @@ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_mi
1032
1032
  _prepare_url_to_download(var, lon_min, lon_max, lat_min, lat_max, ymdh_time_s, None, depth, level, store_path, dataset_name, version_name, check)
1033
1033
  elif int(ymdh_time_s) < int(ymdh_time_e):
1034
1034
  print("Downloading a series of files...")
1035
- time_list = get_time_list(ymdh_time_s, ymdh_time_e, int(download_interval), "hour")
1035
+ time_list = get_time_list(ymdh_time_s, ymdh_time_e, interval_hour, "hour")
1036
1036
  with Progress() as progress:
1037
1037
  task = progress.add_task("[cyan]Downloading...", total=len(time_list))
1038
1038
  if ftimes == 1:
@@ -1050,7 +1050,8 @@ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_mi
1050
1050
  for feature in as_completed(futures):
1051
1051
  _done_callback(feature, progress, task, len(time_list), counter_lock)
1052
1052
  else:
1053
- new_time_list = get_time_list(ymdh_time_s, ymdh_time_e, 3 * ftimes, "hour")
1053
+ # new_time_list = get_time_list(ymdh_time_s, ymdh_time_e, 3 * ftimes, "hour")
1054
+ new_time_list = get_time_list(ymdh_time_s, ymdh_time_e, interval_hour * ftimes, "hour")
1054
1055
  total_num = len(new_time_list)
1055
1056
  if num_workers is None or num_workers <= 1:
1056
1057
  # 串行方式
@@ -1071,7 +1072,7 @@ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_mi
1071
1072
  print("[bold red]Please ensure the time_s is no more than time_e")
1072
1073
 
1073
1074
 
1074
- def download(var, time_s, time_e=None, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level=None, store_path=None, dataset_name=None, version_name=None, num_workers=None, check=False, ftimes=1, idm_engine=None, fill_time=None, download_interval_hour=3):
1075
+ def download(var, time_s, time_e=None, lon_min=0, lon_max=359.92, lat_min=-80, lat_max=90, depth=None, level=None, store_path=None, dataset_name=None, version_name=None, num_workers=None, check=False, ftimes=1, idm_engine=None, fill_time=None, interval_hour=3):
1075
1076
  """
1076
1077
  Description:
1077
1078
  Download the data of single time or a series of time
@@ -1094,7 +1095,7 @@ def download(var, time_s, time_e=None, lon_min=0, lon_max=359.92, lat_min=-80, l
1094
1095
  ftimes: int, the number of time in one file, default is 1, if set to 1, the data of single time will be downloaded; the maximum is 8, if set to 8, the data of 8 times will be downloaded in one file
1095
1096
  idm_engine: str, the IDM engine, default is None, if set, the IDM will be used to download the data; example: "D:\\Programs\\Internet Download Manager\\IDMan.exe"
1096
1097
  fill_time: bool or None, the mode to fill the time, default is None. None: only download the data; True: modify the real time of data to the time in the file name; False: check the time in the file name and the real time of data, if not match, delete the file
1097
- download_interval_hour: int, the interval time to download the data, default is 3, if set, the interval time will be used to download the data; example: 3, 6, ...
1098
+ interval_hour: int, the interval time to download the data, default is 3, if set, the interval time will be used to download the data; example: 3, 6, ...
1098
1099
 
1099
1100
  Returns:
1100
1101
  None
@@ -1180,30 +1181,47 @@ def download(var, time_s, time_e=None, lon_min=0, lon_max=359.92, lat_min=-80, l
1180
1181
 
1181
1182
  global match_time
1182
1183
  match_time = fill_time
1184
+
1185
+ global mark_len
1186
+ mark_len = 150
1183
1187
 
1184
- _download_hourly_func(var, time_s, time_e, lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, num_workers, check, ftimes, download_interval_hour)
1188
+ _download_hourly_func(var, time_s, time_e, lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, num_workers, check, ftimes, int(interval_hour))
1185
1189
 
1186
1190
  if idm_engine is not None:
1191
+ print("[bold #ecdbfe]*" * mark_len)
1192
+ print("[bold #3dfc40]All files have been submitted to IDM for downloading")
1193
+ print("[bold #ecdbfe]*" * mark_len)
1187
1194
  if idm_download_list:
1195
+ file_download_time = 60 # 预设下载时间为1分钟
1188
1196
  for f in idm_download_list:
1197
+ file_download_start_time = time.time()
1189
1198
  wait_success = 0
1190
1199
  success = False
1191
1200
  while not success:
1192
1201
  if check_nc(f):
1193
1202
  count_dict["success"] += 1
1194
1203
  success = True
1204
+ print(f"[bold #3dfc40]File [bold #dfff73]{f} [#3dfc40]has been downloaded successfully")
1205
+ file_download_end_time = time.time()
1206
+ file_download_time = file_download_end_time - file_download_start_time
1207
+ file_download_time = int(file_download_time)
1208
+ print(f"[bold #3dfc40]Time: {file_download_time} seconds")
1209
+ file_download_time = max(60, file_download_time) # 预设下载时间为1分钟起步
1195
1210
  else:
1196
1211
  wait_success += 1
1197
- time.sleep(3)
1198
- if wait_success >= 20:
1212
+ print(f"[bold #ffe5c0]Waiting {file_download_time} seconds to check the file {f}...")
1213
+ time.sleep(file_download_time)
1214
+ if wait_success >= 10:
1199
1215
  success = True
1200
1216
  # print(f'{f} download failed')
1217
+ print(f'[bold #ffe5c0]Waiting for more than 10 times, skipping the file {f}...')
1201
1218
  count_dict["fail"] += 1
1219
+ print('[bold #ecdbfe]-' * mark_len)
1202
1220
 
1203
1221
  count_dict["total"] = count_dict["success"] + count_dict["fail"] + count_dict["skip"] + count_dict["no_data"]
1204
- print("[bold #ecdbfe]-" * 160)
1222
+ print("[bold #ecdbfe]=" * mark_len)
1205
1223
  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']}")
1206
- print("[bold #ecdbfe]-" * 160)
1224
+ print("[bold #ecdbfe]=" * mark_len)
1207
1225
  if count_dict["fail"] > 0:
1208
1226
  print("[bold #be5528]Please try again to download the failed data later")
1209
1227
  if count_dict["no_data"] > 0:
@@ -1213,7 +1231,7 @@ def download(var, time_s, time_e=None, lon_min=0, lon_max=359.92, lat_min=-80, l
1213
1231
  print(f"[bold #f90000]These are {count_dict['no_data']} data that do not exist in any dataset and version")
1214
1232
  for no_data in count_dict["no_data_list"]:
1215
1233
  print(f"[bold #d81b60]{no_data}")
1216
- print("[bold #ecdbfe]-" * 160)
1234
+ print("[bold #ecdbfe]=" * mark_len)
1217
1235
 
1218
1236
 
1219
1237
  def how_to_use():
oafuncs/oa_down/idm.py CHANGED
@@ -2,9 +2,9 @@
2
2
  # coding=utf-8
3
3
  """
4
4
  Author: Liu Kun && 16031215@qq.com
5
- Date: 2025-01-11 16:19:12
5
+ Date: 2025-03-27 16:51:26
6
6
  LastEditors: Liu Kun && 16031215@qq.com
7
- LastEditTime: 2025-01-11 16:25:47
7
+ LastEditTime: 2025-04-01 16:09:03
8
8
  FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_down\\idm.py
9
9
  Description:
10
10
  EditPlatform: vscode
@@ -16,7 +16,6 @@ Python Version: 3.12
16
16
  import datetime
17
17
  import os
18
18
  from subprocess import call
19
-
20
19
  from rich import print
21
20
 
22
21
  __all__ = ["downloader"]
@@ -46,5 +45,11 @@ def downloader(task_url, folder_path, file_name, idm_engine=r"D:\Programs\Intern
46
45
  # 开始任务队列
47
46
  call([idm_engine, "/s"])
48
47
  # print(f"IDM下载器:{file_name}下载任务已添加至队列...")
49
- print("[purple]-" * 50 + f"\n{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" + "[purple]-" * 50)
48
+ # print("[purple]-" * 150 + f"\n{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" + "[purple]-" * 150)
49
+ print("[purple]*" * 100)
50
+ time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
51
+ time_str = time_str.center(100, " ")
52
+ print(f"[bold purple]{time_str}")
50
53
  print(f"[green]IDM Downloader: {file_name} download task has been added to the queue...[/green]")
54
+ print("[purple]*" * 100)
55
+ print('\n')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oafuncs
3
- Version: 0.0.97.10
3
+ Version: 0.0.97.12
4
4
  Summary: Oceanic and Atmospheric Functions
5
5
  Home-page: https://github.com/Industry-Pays/OAFuncs
6
6
  Author: Kun Liu
@@ -1,6 +1,6 @@
1
1
  oafuncs/__init__.py,sha256=T_-VtnWWllV3Q91twT5Yt2sUapeA051QbPNnBxmg9nw,1456
2
2
  oafuncs/oa_cmap.py,sha256=OfJ2DOBOGX5X1GihE6CPcTV8bAFdDqJSXV7vbqUgV9s,7552
3
- oafuncs/oa_data.py,sha256=32elvoBHibTunDXAK9ptQ-e-xrXxKM4GrPiMqWNv_lE,12169
3
+ oafuncs/oa_data.py,sha256=7Mm2tFpKScs7TDgPiHDS0l_xVqb65WZvuQJCZ9BbK5Y,12953
4
4
  oafuncs/oa_date.py,sha256=--3uXYq3_n9HBJbY1io1H1PE-FyiVxbQCyFUcudxQks,3210
5
5
  oafuncs/oa_draw.py,sha256=d23R6OEco7EbvcrL5YsnrSupnKKUn55hLw1B_d-kxOg,12308
6
6
  oafuncs/oa_file.py,sha256=nYTsMataaC790lSqxjuMB4uVqUJz_tMm_kRve4CHql4,17235
@@ -10,14 +10,15 @@ oafuncs/oa_python.py,sha256=Q-6UGGw_dJff7Ef8i87fsLPoGeHV5jBzfb-7HP4THR0,4018
10
10
  oafuncs/_data/OAFuncs.png,sha256=y1_x-mUP3gFjcy6m8FqfvQO_HgjzPhQKfXjnSHjslZE,3436152
11
11
  oafuncs/_data/hycom_3hourly.png,sha256=azt_uPcXtl_8CSKRLLPCIf5pPrcxMiOzvoFQnwb0zUo,12411415
12
12
  oafuncs/_script/auto_optimized_parallel_executor.py,sha256=4QaEk9AM-IneHm8KKSQ6MjSLNSaAWM4AQ-8OWXYdsaI,17300
13
+ oafuncs/_script/cprogressbar.py,sha256=F3LlFsKojP58mqcAqHRw3u-ffftXaYiN5dKj7zDi0iI,5658
13
14
  oafuncs/_script/netcdf_merge.py,sha256=mKHnjStCqP7bwUMVA5k9ZKwT1ZVv1PR-ehMKdpHMJ4s,14439
14
15
  oafuncs/_script/parallel_example_usage.py,sha256=uLvE7iwkMn9Cyq6-wk5_RpbQk7PXM9d16-26lTknW9s,2646
15
16
  oafuncs/_script/plot_dataset.py,sha256=zkSEnO_-biyagorwWXPoihts_cwuvripzEt-l9bHJ2E,13989
16
17
  oafuncs/_script/replace_file_concent.py,sha256=eCFZjnZcwyRvy6b4mmIfBna-kylSZTyJRfgXd6DdCjk,5982
17
18
  oafuncs/oa_down/User_Agent-list.txt,sha256=pazxSip8_lphEBOPHG902zmIBUg8sBKXgmqp_g6j_E4,661062
18
19
  oafuncs/oa_down/__init__.py,sha256=kRX5eTUCbAiz3zTaQM1501paOYS_3fizDN4Pa0mtNUA,585
19
- oafuncs/oa_down/hycom_3hourly.py,sha256=RlNJe5TLth1YjbnlJPgWtxkNKTy7rSYCo9Cwb9iID1s,65571
20
- oafuncs/oa_down/idm.py,sha256=XfYCNnQWADxOhhJd-T8sNYN0nGiRrAs7zbQcsB5-UmI,1668
20
+ oafuncs/oa_down/hycom_3hourly.py,sha256=TnLyXEFJthl4NOeuCXW5DM-h0T6JxhIVATW7XOC4sqw,66837
21
+ oafuncs/oa_down/idm.py,sha256=pqktP4aKDxR3k8XLy9ceQQovvb4jjjT1VGF955PHIG8,1898
21
22
  oafuncs/oa_down/literature.py,sha256=2bF9gSKQbzcci9LcKE81j8JEjIJwON7jbwQB3gDDA3E,11331
22
23
  oafuncs/oa_down/test_ua.py,sha256=0IQq3NjqfNr7KkyjS_U-a4mYu-r-E7gzawwo4IfEa6Y,10851
23
24
  oafuncs/oa_down/user_agent.py,sha256=TsPcAxFmMTYAEHRFjurI1bQBJfDhcA70MdHoUPwQmks,785
@@ -33,8 +34,8 @@ oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw
33
34
  oafuncs/oa_tool/__init__.py,sha256=AvrCNR2-xad9ZRjthIdAoSk8UX4vOpEWLg6CV1NQNKc,161
34
35
  oafuncs/oa_tool/email.py,sha256=4lJxV_KUzhxgLYfVwYTqp0qxRugD7fvsZkXDe5WkUKo,3052
35
36
  oafuncs/oa_tool/parallel.py,sha256=LBFWEKPcILVCbfSulETJE4wGPiOw1P_Fl9DzjYoCqgk,21844
36
- oafuncs-0.0.97.10.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
37
- oafuncs-0.0.97.10.dist-info/METADATA,sha256=_nG65EsnOtswb-cfau1QhHjKq9iuhBPwUpYqp-L7_pw,4226
38
- oafuncs-0.0.97.10.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
39
- oafuncs-0.0.97.10.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
40
- oafuncs-0.0.97.10.dist-info/RECORD,,
37
+ oafuncs-0.0.97.12.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
38
+ oafuncs-0.0.97.12.dist-info/METADATA,sha256=sWGGWvxD_dWTX6bNz5sdMoJe4r3-GemQnSJY2P79dFw,4226
39
+ oafuncs-0.0.97.12.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
40
+ oafuncs-0.0.97.12.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
41
+ oafuncs-0.0.97.12.dist-info/RECORD,,