oafuncs 0.0.97.12__py3-none-any.whl → 0.0.97.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.
@@ -1,14 +1,16 @@
1
1
  # progressbar.py
2
- import sys
2
+ import re
3
3
  import shutil
4
+ import sys
4
5
  import time
5
6
  import warnings
6
- from typing import Iterable, Any, List, Union
7
+ from typing import Any, Iterable, List, Optional, Union
8
+
7
9
  import numpy as np
8
10
 
9
11
  try:
10
- from matplotlib.colors import LinearSegmentedColormap, to_rgb, to_hex
11
- from matplotlib.cm import get_cmap
12
+ import matplotlib
13
+ from matplotlib.colors import LinearSegmentedColormap, to_hex, to_rgb
12
14
  except ImportError:
13
15
  raise ImportError("This module requires matplotlib. Install with: pip install matplotlib")
14
16
 
@@ -26,20 +28,28 @@ class ColorProgressBar:
26
28
  self._last_update = 0
27
29
  self._count = len(iterable) if hasattr(iterable, "__len__") else None
28
30
  self._file = sys.stdout
29
- self._gradient_colors = self._generate_gradient() if cmap else None
31
+ self._gradient_colors = self._generate_gradient() if cmap and self._count else None
30
32
 
31
- def _generate_gradient(self) -> List[str]:
33
+ def _generate_gradient(self) -> Optional[List[str]]:
32
34
  """生成渐变色列表(修复内置colormap支持)"""
33
35
  try:
34
36
  if isinstance(self.cmap, list):
35
37
  cmap = LinearSegmentedColormap.from_list("custom_cmap", self.cmap)
38
+ elif hasattr(self.cmap, "__call__") and hasattr(self.cmap, "N"):
39
+ # 直接处理已经是colormap对象的情况
40
+ cmap = self.cmap
36
41
  else:
37
- # 正确获取Matplotlib内置colormap
38
- cmap = get_cmap(self.cmap)
42
+ # 兼容不同版本的matplotlib
43
+ try:
44
+ # 新版本matplotlib (>=3.6)
45
+ cmap = matplotlib.colormaps[self.cmap]
46
+ except (AttributeError, KeyError):
47
+ # 旧版本matplotlib
48
+ cmap = matplotlib.cm.get_cmap(self.cmap)
39
49
 
40
50
  return [to_hex(cmap(i)) for i in np.linspace(0, 1, self._count)]
41
51
  except Exception as e:
42
- warnings.warn(f"Colormap generation failed: {str(e)}")
52
+ warnings.warn(f"Colormap generation failed: {str(e)}. cmap type: {type(self.cmap)}")
43
53
  return None
44
54
 
45
55
  def _hex_to_ansi(self, hex_color: str) -> str:
@@ -53,10 +63,10 @@ class ColorProgressBar:
53
63
 
54
64
  def _resolve_color(self, index: int) -> str:
55
65
  """解析当前应使用的颜色"""
56
- if self._gradient_colors and index < len(self._gradient_colors):
66
+ if self._gradient_colors and 0 <= index < len(self._gradient_colors):
57
67
  try:
58
68
  return self._hex_to_ansi(self._gradient_colors[index])
59
- except IndexError:
69
+ except (IndexError, ValueError):
60
70
  pass
61
71
 
62
72
  return self._process_color_value(self.base_color)
@@ -80,20 +90,27 @@ class ColorProgressBar:
80
90
  warnings.warn(f"Color parsing failed: {e}, using cyan")
81
91
  return preset_map["cyan"]
82
92
 
93
+ def _strip_ansi(self, text: str) -> str:
94
+ """移除所有ANSI转义序列"""
95
+ ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
96
+ return ansi_escape.sub("", text)
97
+
83
98
  def _format_bar(self, progress: float, width: int) -> str:
84
99
  """格式化进度条显示"""
85
100
  filled = "▊"
86
101
  empty = " "
87
- max_width = width - 50
102
+ # 为其他信息保留更多空间
103
+ max_width = max(10, width - 60) # 至少保留10个字符的进度条
88
104
  filled_length = int(round(max_width * progress))
89
105
  return filled * filled_length + empty * (max_width - filled_length)
90
106
 
91
107
  def _calculate_speed(self, index: int, elapsed: float) -> tuple:
92
108
  """计算速率和剩余时间"""
109
+ # 防止除零错误
93
110
  if index == 0 or elapsed < 1e-6:
94
111
  return 0.0, 0.0
95
112
 
96
- rate = index / elapsed
113
+ rate = index / max(elapsed, 1e-6) # 确保分母不为零
97
114
  remaining = (self._count - index) / rate if self._count else 0
98
115
  return rate, remaining
99
116
 
@@ -102,35 +119,56 @@ class ColorProgressBar:
102
119
  self._last_update = self._start_time
103
120
  reset_code = "\033[0m"
104
121
 
122
+ # 判断是否在终端环境中
123
+ is_terminal = hasattr(self._file, "isatty") and self._file.isatty()
124
+
125
+ try:
126
+ term_width = self.bar_length or (shutil.get_terminal_size().columns if is_terminal else 80)
127
+ except (AttributeError, OSError):
128
+ term_width = 80 # 默认终端宽度
129
+
105
130
  for i, item in enumerate(self.iterable):
106
131
  now = time.time()
107
132
  elapsed = now - self._start_time
108
133
  yield item
109
134
 
110
- if (now - self._last_update) < self.update_interval and i + 1 != self._count:
135
+ # 非终端环境或更新间隔未到时跳过更新
136
+ if not is_terminal or ((now - self._last_update) < self.update_interval and i + 1 != self._count):
111
137
  continue
112
138
 
113
- term_width = self.bar_length or shutil.get_terminal_size().columns
114
139
  progress = (i + 1) / self._count if self._count else 0
115
-
116
140
  current_color = self._resolve_color(i) if self._gradient_colors else self._resolve_color(0)
117
141
 
118
- bar = self._format_bar(progress, term_width)
142
+ # 确保进度条至少有一个字符的宽度
143
+ effective_width = max(15, term_width - 40) # 保留更多空间给信息显示
144
+ bar = self._format_bar(progress, effective_width)
145
+
119
146
  rate, remaining = self._calculate_speed(i + 1, elapsed)
120
147
 
121
148
  count_info = f"{i + 1}/{self._count}" if self._count else str(i + 1)
122
149
  percent = f"{progress:.1%}" if self._count else ""
123
150
  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"
151
+ time_info = f"ETA: {remaining:.1f}s" if self._count and remaining > 0 else f"Elapsed: {elapsed:.1f}s"
125
152
 
126
- line = (f"\r{self.prefix}{current_color}[{bar}]{reset_code} {count_info} {percent} [{time_info} | {rate_info}]").ljust(term_width)
153
+ # 构建新的进度条行
154
+ line = f"{self.prefix}{current_color}[{bar}]{reset_code} {count_info} {percent} [{time_info} | {rate_info}]"
127
155
 
156
+ # 清除之前的行并强制光标回到行首
157
+ self._file.write("\r")
158
+
159
+ # 确保不超出终端宽度
160
+ if len(self._strip_ansi(line)) > term_width:
161
+ line = line[: term_width - 3] + "..."
162
+
163
+ # 输出并强制刷新
128
164
  self._file.write(line)
129
165
  self._file.flush()
130
166
  self._last_update = now
131
167
 
132
- self._file.write("\n")
133
- self._file.flush()
168
+ # 完成后添加换行符
169
+ if is_terminal:
170
+ self._file.write("\n")
171
+ self._file.flush()
134
172
 
135
173
  @classmethod
136
174
  def gradient_color(cls, colors: List[str], n: int) -> List[str]:
@@ -141,10 +179,30 @@ class ColorProgressBar:
141
179
 
142
180
  # 验证示例
143
181
  if __name__ == "__main__":
144
- # 正确使用内置colormap
182
+ # 使用内置colormap示例
183
+ import oafuncs
184
+
185
+ cmap = oafuncs.oa_cmap.get("diverging_1")
186
+ for _ in ColorProgressBar(range(100), cmap=cmap, prefix="Diverging: "):
187
+ time.sleep(0.1)
188
+
145
189
  for _ in ColorProgressBar(range(100), cmap="viridis", prefix="Viridis: "):
146
- time.sleep(0.05)
190
+ time.sleep(0.1)
147
191
 
148
192
  # 使用自定义渐变色
149
193
  for _ in ColorProgressBar(range(50), cmap=["#FF0000", "#0000FF"], prefix="Custom: "):
150
194
  time.sleep(0.1)
195
+
196
+ # 测试无法获取长度的迭代器
197
+ def infinite_generator():
198
+ i = 0
199
+ while True:
200
+ yield i
201
+ i += 1
202
+
203
+ # 限制为20个元素,但进度条不知道总长度
204
+ gen = infinite_generator()
205
+ for i, _ in enumerate(ColorProgressBar(gen, prefix="Unknown length: ")):
206
+ if i >= 20:
207
+ break
208
+ time.sleep(0.1)
@@ -13,9 +13,6 @@ SystemInfo: Windows 11
13
13
  Python Version: 3.12
14
14
  """
15
15
 
16
-
17
-
18
-
19
16
  import datetime
20
17
  import os
21
18
  import random
@@ -711,13 +708,13 @@ def _download_file(target_url, store_path, file_name, check=False):
711
708
  file_name_split = file_name_split[:-1]
712
709
  # same_file = f"{file_name_split[0]}_{file_name_split[1]}*nc"
713
710
  same_file = "_".join(file_name_split) + "*nc"
714
-
711
+
715
712
  if match_time is not None:
716
713
  if check_nc(fname):
717
714
  if not _check_ftime(fname, if_print=True):
718
715
  if match_time:
719
716
  _correct_time(fname)
720
- count_dict['skip'] += 1
717
+ count_dict["skip"] += 1
721
718
  else:
722
719
  _clear_existing_file(fname)
723
720
  # print(f"[bold #ffe5c0]File time error, {fname}")
@@ -997,7 +994,7 @@ def _done_callback(future, progress, task, total, counter_lock):
997
994
  global parallel_counter
998
995
  with counter_lock:
999
996
  parallel_counter += 1
1000
- progress.update(task, advance=1, description=f"[cyan]Downloading... {parallel_counter}/{total}")
997
+ progress.update(task, advance=1, description=f"[cyan]{bar_desc} {parallel_counter}/{total}")
1001
998
 
1002
999
 
1003
1000
  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):
@@ -1034,19 +1031,19 @@ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_mi
1034
1031
  print("Downloading a series of files...")
1035
1032
  time_list = get_time_list(ymdh_time_s, ymdh_time_e, interval_hour, "hour")
1036
1033
  with Progress() as progress:
1037
- task = progress.add_task("[cyan]Downloading...", total=len(time_list))
1034
+ task = progress.add_task(f"[cyan]{bar_desc}", total=len(time_list))
1038
1035
  if ftimes == 1:
1039
1036
  if num_workers is None or num_workers <= 1:
1040
1037
  # 串行方式
1041
1038
  for i, time_str in enumerate(time_list):
1042
1039
  _prepare_url_to_download(var, lon_min, lon_max, lat_min, lat_max, time_str, None, depth, level, store_path, dataset_name, version_name, check)
1043
- progress.update(task, advance=1, description=f"[cyan]Downloading... {i + 1}/{len(time_list)}")
1040
+ progress.update(task, advance=1, description=f"[cyan]{bar_desc} {i + 1}/{len(time_list)}")
1044
1041
  else:
1045
1042
  # 并行方式
1046
1043
  with ThreadPoolExecutor(max_workers=num_workers) as executor:
1047
1044
  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, check) for time_str in time_list]
1048
1045
  """ for i, future in enumerate(futures):
1049
- future.add_done_callback(lambda _: progress.update(task, advance=1, description=f"[cyan]Downloading... {i+1}/{len(time_list)}")) """
1046
+ future.add_done_callback(lambda _: progress.update(task, advance=1, description=f"[cyan]{bar_desc} {i+1}/{len(time_list)}")) """
1050
1047
  for feature in as_completed(futures):
1051
1048
  _done_callback(feature, progress, task, len(time_list), counter_lock)
1052
1049
  else:
@@ -1059,13 +1056,13 @@ def _download_hourly_func(var, time_s, time_e, lon_min=0, lon_max=359.92, lat_mi
1059
1056
  time_str_end_index = int(min(len(time_list) - 1, int(i * ftimes + ftimes - 1)))
1060
1057
  time_str_end = time_list[time_str_end_index]
1061
1058
  _prepare_url_to_download(var, lon_min, lon_max, lat_min, lat_max, time_str, time_str_end, depth, level, store_path, dataset_name, version_name, check)
1062
- progress.update(task, advance=1, description=f"[cyan]Downloading... {i + 1}/{total_num}")
1059
+ progress.update(task, advance=1, description=f"[cyan]{bar_desc} {i + 1}/{total_num}")
1063
1060
  else:
1064
1061
  # 并行方式
1065
1062
  with ThreadPoolExecutor(max_workers=num_workers) as executor:
1066
1063
  futures = [executor.submit(_download_task, var, new_time_list[i], time_list[int(min(len(time_list) - 1, int(i * ftimes + ftimes - 1)))], lon_min, lon_max, lat_min, lat_max, depth, level, store_path, dataset_name, version_name, check) for i in range(total_num)]
1067
1064
  """ for i, future in enumerate(futures):
1068
- future.add_done_callback(lambda _: progress.update(task, advance=1, description=f"[cyan]Downloading... {i+1}/{total_num}")) """
1065
+ future.add_done_callback(lambda _: progress.update(task, advance=1, description=f"[cyan]{bar_desc} {i+1}/{total_num}")) """
1069
1066
  for feature in as_completed(futures):
1070
1067
  _done_callback(feature, progress, task, len(time_list), counter_lock)
1071
1068
  else:
@@ -1100,6 +1097,9 @@ def download(var, time_s, time_e=None, lon_min=0, lon_max=359.92, lat_min=-80, l
1100
1097
  Returns:
1101
1098
  None
1102
1099
  """
1100
+ from oafuncs.oa_data import pbar
1101
+ from oafuncs.oa_cmap import get as get_cmap
1102
+
1103
1103
  _get_initial_data()
1104
1104
 
1105
1105
  # 打印信息并处理数据集和版本名称
@@ -1166,57 +1166,71 @@ def download(var, time_s, time_e=None, lon_min=0, lon_max=359.92, lat_min=-80, l
1166
1166
 
1167
1167
  global fsize_dict_lock
1168
1168
  fsize_dict_lock = Lock()
1169
-
1169
+
1170
1170
  if fill_time is not None:
1171
1171
  num_workers = 1
1172
1172
 
1173
- global use_idm, given_idm_engine, idm_download_list
1173
+ global use_idm, given_idm_engine, idm_download_list, bar_desc
1174
1174
  if idm_engine is not None:
1175
1175
  use_idm = True
1176
1176
  num_workers = 1
1177
1177
  given_idm_engine = idm_engine
1178
1178
  idm_download_list = []
1179
+ bar_desc = "Submitting to IDM ..."
1179
1180
  else:
1180
1181
  use_idm = False
1182
+ bar_desc = "Downloading ..."
1181
1183
 
1182
1184
  global match_time
1183
1185
  match_time = fill_time
1184
-
1186
+
1185
1187
  global mark_len
1186
- mark_len = 150
1188
+ mark_len = 100
1187
1189
 
1188
1190
  _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))
1189
1191
 
1190
1192
  if idm_engine is not None:
1191
1193
  print("[bold #ecdbfe]*" * mark_len)
1192
- print("[bold #3dfc40]All files have been submitted to IDM for downloading")
1194
+ str_info = "All files have been submitted to IDM for downloading"
1195
+ str_info = str_info.center(mark_len, "*")
1196
+ print(f"[bold #3dfc40]{str_info}")
1193
1197
  print("[bold #ecdbfe]*" * mark_len)
1194
1198
  if idm_download_list:
1195
- file_download_time = 60 # 预设下载时间为1分钟
1196
- for f in idm_download_list:
1199
+ """ file_download_time = 60 # 预设下载时间为1分钟
1200
+ for f in pbar(idm_download_list,cmap='bwr',prefix='HYCOM: '):
1197
1201
  file_download_start_time = time.time()
1198
1202
  wait_success = 0
1199
1203
  success = False
1200
1204
  while not success:
1201
- if check_nc(f):
1205
+ if check_nc(f,print_switch=False):
1202
1206
  count_dict["success"] += 1
1203
1207
  success = True
1204
- print(f"[bold #3dfc40]File [bold #dfff73]{f} [#3dfc40]has been downloaded successfully")
1208
+ # print(f"[bold #3dfc40]File [bold #dfff73]{f} [#3dfc40]has been downloaded successfully")
1205
1209
  file_download_end_time = time.time()
1206
1210
  file_download_time = file_download_end_time - file_download_start_time
1207
1211
  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分钟起步
1212
+ # print(f"[bold #3dfc40]Time: {file_download_time} seconds")
1213
+ file_download_time = max(60, file_download_time) # 预设下载时间为1分钟起步
1210
1214
  else:
1211
1215
  wait_success += 1
1212
- print(f"[bold #ffe5c0]Waiting {file_download_time} seconds to check the file {f}...")
1216
+ # print(f"[bold #ffe5c0]Waiting {file_download_time} seconds to check the file {f}...")
1213
1217
  time.sleep(file_download_time)
1214
1218
  if wait_success >= 10:
1215
1219
  success = True
1216
1220
  # print(f'{f} download failed')
1217
- print(f'[bold #ffe5c0]Waiting for more than 10 times, skipping the file {f}...')
1221
+ print(f"[bold #ffe5c0]Waiting for more than 10 times, skipping the file {f}...")
1218
1222
  count_dict["fail"] += 1
1219
- print('[bold #ecdbfe]-' * mark_len)
1223
+ # print("[bold #ecdbfe]-" * mark_len) """
1224
+ remain_list = idm_download_list.copy()
1225
+ for f_count in pbar(range(len(idm_download_list)), cmap=get_cmap('diverging_1'), prefix="HYCOM: "):
1226
+ success = False
1227
+ while not success:
1228
+ for f in remain_list:
1229
+ if check_nc(f, print_switch=False):
1230
+ count_dict["success"] += 1
1231
+ success = True
1232
+ remain_list.remove(f)
1233
+ break
1220
1234
 
1221
1235
  count_dict["total"] = count_dict["success"] + count_dict["fail"] + count_dict["skip"] + count_dict["no_data"]
1222
1236
  print("[bold #ecdbfe]=" * mark_len)
oafuncs/oa_down/idm.py CHANGED
@@ -4,7 +4,7 @@
4
4
  Author: Liu Kun && 16031215@qq.com
5
5
  Date: 2025-03-27 16:51:26
6
6
  LastEditors: Liu Kun && 16031215@qq.com
7
- LastEditTime: 2025-04-01 16:09:03
7
+ LastEditTime: 2025-04-01 22:31:39
8
8
  FilePath: \\Python\\My_Funcs\\OAFuncs\\oafuncs\\oa_down\\idm.py
9
9
  Description:
10
10
  EditPlatform: vscode
@@ -13,9 +13,11 @@ SystemInfo: Windows 11
13
13
  Python Version: 3.12
14
14
  """
15
15
 
16
+
16
17
  import datetime
17
18
  import os
18
19
  from subprocess import call
20
+
19
21
  from rich import print
20
22
 
21
23
  __all__ = ["downloader"]
@@ -50,6 +52,6 @@ def downloader(task_url, folder_path, file_name, idm_engine=r"D:\Programs\Intern
50
52
  time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
51
53
  time_str = time_str.center(100, " ")
52
54
  print(f"[bold purple]{time_str}")
53
- print(f"[green]IDM Downloader: {file_name} download task has been added to the queue...[/green]")
55
+ print(f"[green]IDM Downloader: {file_name} download task has been added to the queue ...[/green]")
54
56
  print("[purple]*" * 100)
55
- print('\n')
57
+ print("\n")
oafuncs/oa_draw.py CHANGED
@@ -165,13 +165,19 @@ def add_lonlat_unit(lon=None, lat=None, decimal=2):
165
165
 
166
166
 
167
167
  # ** 添加网格线
168
- def add_gridlines(ax, projection=ccrs.PlateCarree(), color="k", alpha=0.5, linestyle="--", linewidth=0.5):
168
+ def add_gridlines(ax, xline=None, yline=None, projection=ccrs.PlateCarree(), color="k", alpha=0.5, linestyle="--", linewidth=0.5):
169
+ from matplotlib import ticker as mticker
169
170
  # add gridlines
170
171
  gl = ax.gridlines(crs=projection, draw_labels=True, linewidth=linewidth, color=color, alpha=alpha, linestyle=linestyle)
171
172
  gl.right_labels = False
172
173
  gl.top_labels = False
173
174
  gl.xformatter = LongitudeFormatter(zero_direction_label=False)
174
175
  gl.yformatter = LatitudeFormatter()
176
+
177
+ if xline is not None:
178
+ gl.xlocator = mticker.FixedLocator(np.array(xline))
179
+ if yline is not None:
180
+ gl.ylocator = mticker.FixedLocator(np.array(yline))
175
181
 
176
182
  return ax, gl
177
183
 
@@ -186,7 +192,7 @@ def add_cartopy(ax, lon=None, lat=None, projection=ccrs.PlateCarree(), gridlines
186
192
 
187
193
  # add gridlines
188
194
  if gridlines:
189
- ax, gl = add_gridlines(ax, projection)
195
+ ax, gl = add_gridlines(ax, projection=projection)
190
196
 
191
197
  # set longitude and latitude format
192
198
  lon_formatter = LongitudeFormatter(zero_direction_label=False)
oafuncs/oa_nc.py CHANGED
@@ -328,7 +328,7 @@ def rename(ncfile_path, old_name, new_name):
328
328
  print(f"An error occurred: {e}")
329
329
 
330
330
 
331
- def check(ncfile: str, delete_switch: bool = False) -> bool:
331
+ def check(ncfile: str, delete_switch: bool = False, print_switch: bool = True) -> bool:
332
332
  """
333
333
  Check if a NetCDF file is corrupted with enhanced error handling.
334
334
 
@@ -337,9 +337,10 @@ def check(ncfile: str, delete_switch: bool = False) -> bool:
337
337
  is_valid = False
338
338
 
339
339
  if not os.path.exists(ncfile):
340
- print(f"[#ffeac5]Local file missing: [#009d88]{ncfile}")
341
- # 提示:提示文件缺失也许是正常的,这只是检查文件是否存在于本地
342
- print("[#d6d9fd]Note: File missing may be normal, this is just to check if the file exists locally.")
340
+ if print_switch:
341
+ print(f"[#ffeac5]Local file missing: [#009d88]{ncfile}")
342
+ # 提示:提示文件缺失也许是正常的,这只是检查文件是否存在于本地
343
+ print("[#d6d9fd]Note: File missing may be normal, this is just to check if the file exists locally.")
343
344
  return False
344
345
 
345
346
  try:
@@ -352,7 +353,8 @@ def check(ncfile: str, delete_switch: bool = False) -> bool:
352
353
  # 二次验证确保变量可访问
353
354
  with nc.Dataset(ncfile, "r") as ds_verify:
354
355
  if not ds_verify.variables:
355
- print(f"Empty variables: {ncfile}")
356
+ if print_switch:
357
+ print(f"[red]Empty variables: {ncfile}[/red]")
356
358
  else:
357
359
  # 尝试访问元数据
358
360
  _ = ds_verify.__dict__
@@ -363,19 +365,23 @@ def check(ncfile: str, delete_switch: bool = False) -> bool:
363
365
  is_valid = True
364
366
 
365
367
  except Exception as e: # 捕获所有异常类型
366
- print(f"HDF5 validation failed for {ncfile}: {str(e)}")
368
+ if print_switch:
369
+ print(f"[red]HDF5 validation failed for {ncfile}: {str(e)}[/red]")
367
370
  error_type = type(e).__name__
368
371
  if "HDF5" in error_type or "h5" in error_type.lower():
369
- print(f"Critical HDF5 structure error detected in {ncfile}")
372
+ if print_switch:
373
+ print(f"[red]Critical HDF5 structure error detected in {ncfile}[/red]")
370
374
 
371
375
  # 安全删除流程
372
376
  if not is_valid:
373
377
  if delete_switch:
374
378
  try:
375
379
  os.remove(ncfile)
376
- print(f"Removed corrupted: {ncfile}")
380
+ if print_switch:
381
+ print(f"[red]Removed corrupted file: {ncfile}[/red]")
377
382
  except Exception as del_error:
378
- print(f"Delete failed: {ncfile} - {str(del_error)}")
383
+ if print_switch:
384
+ print(f"[red]Failed to delete corrupted file: {ncfile} - {str(del_error)}[/red]")
379
385
  return False
380
386
 
381
387
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oafuncs
3
- Version: 0.0.97.12
3
+ Version: 0.0.97.13
4
4
  Summary: Oceanic and Atmospheric Functions
5
5
  Home-page: https://github.com/Industry-Pays/OAFuncs
6
6
  Author: Kun Liu
@@ -2,23 +2,23 @@ oafuncs/__init__.py,sha256=T_-VtnWWllV3Q91twT5Yt2sUapeA051QbPNnBxmg9nw,1456
2
2
  oafuncs/oa_cmap.py,sha256=OfJ2DOBOGX5X1GihE6CPcTV8bAFdDqJSXV7vbqUgV9s,7552
3
3
  oafuncs/oa_data.py,sha256=7Mm2tFpKScs7TDgPiHDS0l_xVqb65WZvuQJCZ9BbK5Y,12953
4
4
  oafuncs/oa_date.py,sha256=--3uXYq3_n9HBJbY1io1H1PE-FyiVxbQCyFUcudxQks,3210
5
- oafuncs/oa_draw.py,sha256=d23R6OEco7EbvcrL5YsnrSupnKKUn55hLw1B_d-kxOg,12308
5
+ oafuncs/oa_draw.py,sha256=mpDiyVMi8-CDfbWWnuE8uXt0aShpW_7AgiBDkb1Mrvk,12571
6
6
  oafuncs/oa_file.py,sha256=nYTsMataaC790lSqxjuMB4uVqUJz_tMm_kRve4CHql4,17235
7
7
  oafuncs/oa_help.py,sha256=loyzTbjU_0VpSIBvAEUA_tqxG8MVsO0xFE_2hgQ3zMw,4188
8
- oafuncs/oa_nc.py,sha256=xouqfEFa1eSExP_ad09JQM5b0rpfPAHEFB7ctg7DkPE,18718
8
+ oafuncs/oa_nc.py,sha256=fV2nPasL-PhE48dppjiG-L1GhDGUHQ-2qdoZt98o-Us,19039
9
9
  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
+ oafuncs/_script/cprogressbar.py,sha256=y5H6TZde2UzFevdIJZc87r0NGzyaR9b46_Bbm-G4lZE,7991
14
14
  oafuncs/_script/netcdf_merge.py,sha256=mKHnjStCqP7bwUMVA5k9ZKwT1ZVv1PR-ehMKdpHMJ4s,14439
15
15
  oafuncs/_script/parallel_example_usage.py,sha256=uLvE7iwkMn9Cyq6-wk5_RpbQk7PXM9d16-26lTknW9s,2646
16
16
  oafuncs/_script/plot_dataset.py,sha256=zkSEnO_-biyagorwWXPoihts_cwuvripzEt-l9bHJ2E,13989
17
17
  oafuncs/_script/replace_file_concent.py,sha256=eCFZjnZcwyRvy6b4mmIfBna-kylSZTyJRfgXd6DdCjk,5982
18
18
  oafuncs/oa_down/User_Agent-list.txt,sha256=pazxSip8_lphEBOPHG902zmIBUg8sBKXgmqp_g6j_E4,661062
19
19
  oafuncs/oa_down/__init__.py,sha256=kRX5eTUCbAiz3zTaQM1501paOYS_3fizDN4Pa0mtNUA,585
20
- oafuncs/oa_down/hycom_3hourly.py,sha256=TnLyXEFJthl4NOeuCXW5DM-h0T6JxhIVATW7XOC4sqw,66837
21
- oafuncs/oa_down/idm.py,sha256=pqktP4aKDxR3k8XLy9ceQQovvb4jjjT1VGF955PHIG8,1898
20
+ oafuncs/oa_down/hycom_3hourly.py,sha256=uLXKioUQO_UtXtXFa4MWolr4a6AQiI1bf-s7NuQGA-U,67661
21
+ oafuncs/oa_down/idm.py,sha256=6eKsbGZ91_187_jJawUc6lqKRdUTse6EfUJnlaSl5mo,1903
22
22
  oafuncs/oa_down/literature.py,sha256=2bF9gSKQbzcci9LcKE81j8JEjIJwON7jbwQB3gDDA3E,11331
23
23
  oafuncs/oa_down/test_ua.py,sha256=0IQq3NjqfNr7KkyjS_U-a4mYu-r-E7gzawwo4IfEa6Y,10851
24
24
  oafuncs/oa_down/user_agent.py,sha256=TsPcAxFmMTYAEHRFjurI1bQBJfDhcA70MdHoUPwQmks,785
@@ -34,8 +34,8 @@ oafuncs/oa_sign/scientific.py,sha256=a4JxOBgm9vzNZKpJ_GQIQf7cokkraV5nh23HGbmTYKw
34
34
  oafuncs/oa_tool/__init__.py,sha256=AvrCNR2-xad9ZRjthIdAoSk8UX4vOpEWLg6CV1NQNKc,161
35
35
  oafuncs/oa_tool/email.py,sha256=4lJxV_KUzhxgLYfVwYTqp0qxRugD7fvsZkXDe5WkUKo,3052
36
36
  oafuncs/oa_tool/parallel.py,sha256=LBFWEKPcILVCbfSulETJE4wGPiOw1P_Fl9DzjYoCqgk,21844
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,,
37
+ oafuncs-0.0.97.13.dist-info/licenses/LICENSE.txt,sha256=rMtLpVg8sKiSlwClfR9w_Dd_5WubTQgoOzE2PDFxzs4,1074
38
+ oafuncs-0.0.97.13.dist-info/METADATA,sha256=fvNNlCEexog-Km0dPu9b4o2G0ZmFqnmliyko-SJtdSg,4226
39
+ oafuncs-0.0.97.13.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
40
+ oafuncs-0.0.97.13.dist-info/top_level.txt,sha256=bgC35QkXbN4EmPHEveg_xGIZ5i9NNPYWqtJqaKqTPsQ,8
41
+ oafuncs-0.0.97.13.dist-info/RECORD,,