shancx 1.9.33.219__py3-none-any.whl → 1.9.33.222__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.
shancx/NN/chainMul.py ADDED
@@ -0,0 +1,175 @@
1
+ import subprocess
2
+ import time
3
+ import logging
4
+ import os
5
+ import argparse
6
+ import datetime
7
+ import traceback
8
+ from dateutil.relativedelta import relativedelta
9
+ import pandas as pd
10
+ from shancx.NN import Mul_TH
11
+ from shancx.NN import _loggersPlus
12
+ from shancx.NN import cleanupLogs
13
+ from shancx.sendM import sendMES
14
+ BASE_DIR = '/mnt/wtx_weather_forecast/scx/sever7/product_log_scx/code06_re2_cp1/exam/mk_trainsatRadarMSG1'
15
+ PYTHON_ENV = '/home/scx/miniconda3/envs/mqpf/bin/python'
16
+ DEFAULT_GPU = '0'
17
+ DEFAULT_TIMEOUT = 2400
18
+ SCRIPT_DELAY = 2
19
+ # minutedict = {"20":8,"30":6,"40":4,"50":2,"0":0}
20
+ minutedict = {"0": 0 }
21
+ class PipelineExecutor:
22
+ def __init__(self, UTC, sat_cd, gpu=DEFAULT_GPU):
23
+ self.UTCstr = UTC.strftime("%Y%m%d%H%M")
24
+ self.sat_cd = sat_cd
25
+ self.gpu = gpu
26
+ self.produce_time= self.producetime(UTC)
27
+ self.scripts = self._initialize_scripts()
28
+ def producetime(self,UTC):
29
+ _minute = UTC.minute
30
+ _minute = minutedict.get(str(_minute),None)
31
+ if _minute is not None :
32
+ start_time = UTC - relativedelta(minutes=_minute) # "20":8 indicates that the step 2 command is executed at the 12-minute mark, which is between 20 and 10 minutes.
33
+ return start_time
34
+ else:
35
+ return None
36
+ def _initialize_scripts(self):
37
+ #step 1 command
38
+ scripts = [
39
+ {
40
+ 'name': 'MSGsat',
41
+ 'cmd': f"cd {os.path.join(BASE_DIR, 'makeMSGnc')} && {PYTHON_ENV} MSGsat.py --times {self.UTCstr[:12]}",
42
+ 'timeout': DEFAULT_TIMEOUT
43
+ }
44
+ ]
45
+ #step 2 command
46
+ if self.produce_time is not None:
47
+ times_str = self.produce_time.strftime("%Y%m%d%H%M")[:12]
48
+ scripts.extend([
49
+ # {
50
+ # 'name': 'mainSAT',
51
+ # 'cmd': f"cd {os.path.join('/mnt/wtx_weather_forecast/scx', 'mqpf_GEOSH9SEAStestCal')} && {PYTHON_ENV} mainSAT.py --times {times_str[:12]} --satcd H9SEAS --sepSec 360 --gpu '{self.gpu}' --isOverwrite --classer 'WT_RTH9SEAS'",
52
+ # 'timeout': DEFAULT_TIMEOUT
53
+ # },
54
+ # {
55
+ # 'name': 'mainSAT',
56
+ # 'cmd': f"cd {os.path.join('/mnt/wtx_weather_forecast/scx', 'mqpf_GEOSH9SEAStestCal')} && {PYTHON_ENV} mainSAT.py --times {times_str[:12]} --satcd H9CHNNEAS --sepSec 360 --gpu '{self.gpu}' --isOverwrite --classer 'WT_RTH9OC'",
57
+ # 'timeout': DEFAULT_TIMEOUT
58
+ # },
59
+ # {
60
+ # 'name': 'mainSAT',
61
+ # 'cmd': f"cd {os.path.join('/mnt/wtx_weather_forecast/scx', 'mqpf_GEOSH9SEAStestCal')} && {PYTHON_ENV} mainSAT.py --times {times_str[:12]} --satcd H9OC --sepSec 360 --gpu '{self.gpu}' --isOverwrite --classer 'WT_RTH9CHNNEAS'",
62
+ # 'timeout': DEFAULT_TIMEOUT
63
+ # },
64
+ # # [
65
+ # # # {
66
+ # # # 'name': 'satPzlSATREF',
67
+ # # # 'cmd': f"cd {os.path.join(BASE_DIR, 'SawPuz')} && {PYTHON_ENV} satPzlSAT.py --times {times_str[:12]} --satcd '{self.sat_cd}' --mqpf_cd 'REF'",
68
+ # # # 'timeout': DEFAULT_TIMEOUT
69
+ # # # },
70
+ # # # {
71
+ # # # 'name': 'satPzlSATQPF',
72
+ # # # 'cmd': f"cd {os.path.join(BASE_DIR, 'SawPuz')} && {PYTHON_ENV} satPzlSAT.py --times {times_str[:12]} --satcd '{self.sat_cd}' --mqpf_cd 'QPF' --isUpload ",
73
+ # # # 'timeout': DEFAULT_TIMEOUT
74
+ # # # }
75
+ # # ]
76
+ ])
77
+ else:
78
+ logger.warning("produce_time is None, skipping mainSAT, satPzlSATREF and satPzlSATQPF command execution")
79
+ return scripts
80
+ def execute_script(self, conf):
81
+ script_info = conf[0]
82
+ script_name = script_info['name']
83
+ timeout = script_info['timeout']
84
+ logger.info(f"Starting to execute script: {script_name}")
85
+ try:
86
+ result = subprocess.run(
87
+ script_info['cmd'],
88
+ shell=True,
89
+ timeout=timeout,
90
+ check=False,
91
+ stdout=subprocess.PIPE,
92
+ stderr=subprocess.PIPE,
93
+ text=True
94
+ )
95
+ if result.returncode != 0:
96
+ logger.error(f"Script {script_name} execution failed, return code: {result.returncode}")
97
+ if result.stdout.strip():
98
+ logger.error(f"Output before failure:\n{result.stdout}")
99
+ if result.stderr.strip():
100
+ logger.error(f"Error output:\n{result.stderr}")
101
+ logger.error(f"Traceback:\n{traceback.format_exc()}")
102
+ return False
103
+ # Success case
104
+ if result.stdout.strip():
105
+ logger.debug(f"[{script_name}] Output:\n{result.stdout}")
106
+ if result.stderr.strip():
107
+ logger.warning(f"[{script_name}] Warning output:\n{result.stderr}")
108
+ logger.info(f"Script {script_name} executed successfully")
109
+ return True
110
+ except Exception as e:
111
+ logger.error(f"Script {script_name} execution exception: {str(e)}")
112
+ logger.error(f"Traceback:\n{traceback.format_exc()}")
113
+ sendMES(f"{traceback.format_exc()} ",NN="MT1")
114
+ return False
115
+ def run_pipeline(self):
116
+ """Execute complete script pipeline"""
117
+ logger.info(f"Starting to process time slot: {self.UTCstr}, satellite: {self.sat_cd}")
118
+ for i, script in enumerate(self.scripts, 1):
119
+ if isinstance(script, list):
120
+ logger.info(f"Executing step {i}/{len(self.scripts)}: satPzlSAT")
121
+ Mul_TH(self.execute_script,[script])
122
+ else:
123
+ logger.info(f"Executing step {i}/{len(self.scripts)}: {script['name']}")
124
+ if not self.execute_script((script,)):
125
+ logger.error(f"Pipeline interrupted at {script['name']}, processing failed")
126
+ return False
127
+ if i < len(self.scripts):
128
+ time.sleep(SCRIPT_DELAY)
129
+ logger.info(f"Time slot {self.UTCstr} processing completed")
130
+ return True
131
+ def main(conf):
132
+ utc,sat_cd,gpu = conf[0],conf[1],conf[2]
133
+ executor = PipelineExecutor(utc, sat_cd, gpu)
134
+ return executor.run_pipeline()
135
+ def options():
136
+ parser = argparse.ArgumentParser(description='Pipeline Cascade time command execution')
137
+ parser.add_argument('--times', type=str, default='202412010000,202508010000')
138
+ parser.add_argument('--sat_cd', type=str, default='MSG')
139
+ parser.add_argument('--gpu', type=str, default='0')
140
+ config= parser.parse_args()
141
+ print(config)
142
+ config.times = config.times.split(",")
143
+ if len(config.times) == 1:
144
+ config.times = [config.times[0], config.times[0]]
145
+ config.times = [datetime.datetime.strptime(config.times[0], "%Y%m%d%H%M"),
146
+ datetime.datetime.strptime(config.times[1], "%Y%m%d%H%M")]
147
+ return config
148
+ if __name__ == "__main__":
149
+ cfg = options()
150
+ sUTC = cfg.times[0]
151
+ eUTC = cfg.times[-1]
152
+ sat_cd = cfg.sat_cd
153
+ gpu =cfg.gpu
154
+ sUTCstr = sUTC.strftime("%Y%m%d%H%M")
155
+ dir_ = f"./logs/{sat_cd}"
156
+ logger = _loggersPlus(root = dir_ , phase=f"{sUTCstr}_Pipeline")
157
+ from shancx.NN import cleanupLogs
158
+ stats = cleanupLogs(dir_,30, '*.log', False, False)
159
+ logging.info(f"clean={stats['total_dirs']}, cleanfile={stats['deleted_files']}, error={len(stats['errors'])}")
160
+
161
+ timeList = pd.date_range(sUTC, eUTC, freq='30min')
162
+ # filtered_times = [t for t in timeList if t.hour % 4 == 0 and t.minute == 0] #t.mintues
163
+ # result_times = []
164
+ # for t in filtered_times:
165
+ # result_times.extend(pd.date_range(t - pd.Timedelta(minutes=30), t, freq='10T'))
166
+ # for UTC in result_times:
167
+ # main((UTC,sat_cd,gpu))
168
+ Mul_TH(main,[timeList,[sat_cd],[gpu]],2)
169
+
170
+
171
+
172
+
173
+
174
+
175
+
shancx/Plot/plotGlobal.py CHANGED
@@ -11,7 +11,7 @@ import cartopy.feature as cfeature
11
11
  from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
12
12
  from hjnwtx.colormap import cmp_hjnwtx
13
13
  import os
14
- def plotGlobal(b, latArr1, lonArr1, cmap='summer', title='Global QPF Data Visualization',saveDir = "./plotGlobal",ty=None ):
14
+ def plotGlobal(b, latArr1, lonArr1, cmap='summer', title='Global QPF Data Visualization',saveDir = "./plotGlobal",ty=None,name="plotGlobal" ):
15
15
  now_str = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
16
16
  plt.figure(figsize=(20, 10), dpi=100)
17
17
  ax = plt.axes(projection=ccrs.PlateCarree())
@@ -28,14 +28,29 @@ def plotGlobal(b, latArr1, lonArr1, cmap='summer', title='Global QPF Data Visual
28
28
  "pre": cmp_hjnwtx["pre_tqw"],
29
29
  None: 'summer'
30
30
  }.get(ty)
31
+
32
+ minmax = {
33
+ "radar": [0,80],
34
+ "pre": [0,20],
35
+ None: [np.nanmin(b),np.nanmax(b)]
36
+ }.get(ty)
37
+
38
+ setlabel = {
39
+ "radar": 'Composite Reflectivity (Radar)\nUnit: (dBZ)',
40
+ "pre": 'Precipitation\nUnit: (mm)',
41
+ None: 'Data'
42
+ }.get(ty)
43
+
31
44
  img = ax.pcolormesh(lon_grid[::stride, ::stride],
32
45
  lat_grid[::stride, ::stride],
33
46
  b[::stride, ::stride],
34
47
  cmap=cmap,
35
48
  shading='auto',
49
+ vmin=minmax[0],
50
+ vmax=minmax[1],
36
51
  transform=ccrs.PlateCarree())
37
52
  cbar = plt.colorbar(img, ax=ax, orientation='vertical', pad=0.05, shrink=0.6)
38
- cbar.set_label('Value Scale', fontsize=12)
53
+ cbar.set_label(setlabel, fontsize=12)
39
54
  ax.set_xticks(np.arange(-180, 181, 30), crs=ccrs.PlateCarree())
40
55
  ax.set_yticks(np.arange(-90, 91, 15), crs=ccrs.PlateCarree())
41
56
  ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True))
@@ -45,15 +60,108 @@ def plotGlobal(b, latArr1, lonArr1, cmap='summer', title='Global QPF Data Visual
45
60
  ax.set_global()
46
61
  plt.tight_layout()
47
62
  os.makedirs(saveDir, exist_ok=True)
48
- plt.savefig(f"./{saveDir}/plotScatter_glob{now_str}.png", dpi=300, bbox_inches="tight")
63
+ plt.savefig(f"./{saveDir}/plotGlobal_glob{now_str}_{name}.png", dpi=300, bbox_inches="tight")
49
64
  plt.close()
50
65
 
51
66
  """
52
67
  plotGlobal(b, latArr1, lonArr1,
53
68
  title='Global Meteorological Data',ty="radar")
54
-
55
69
  """
56
70
 
71
+ import ssl
72
+ import urllib.request
73
+ ssl._create_default_https_context = ssl._create_unverified_context
74
+ import datetime
75
+ import numpy as np
76
+ import matplotlib.pyplot as plt
77
+ import cartopy.crs as ccrs
78
+ import cartopy.feature as cfeature
79
+ from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
80
+ from hjnwtx.colormap import cmp_hjnwtx
81
+ import os
82
+ def plotGlobalTtf(b, latArr1, lonArr1, cmap='summer', title='Global QPF Data Visualization', saveDir="./plotGlobal", ty=None, name=1,font_path=None):
83
+ now_str = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
84
+ import matplotlib.pyplot as plt
85
+ import matplotlib
86
+ import matplotlib.font_manager as fm
87
+ font_path = "/mnt/wtx_weather_forecast/scx/sever7/微软雅黑.ttf" if font_path is None else font_path
88
+ font_kwargs = {}
89
+ if os.path.exists(font_path):
90
+ try:
91
+ fm.fontManager.addfont(font_path)
92
+ font_prop = fm.FontProperties(fname=font_path)
93
+ font_name = font_prop.get_name()
94
+ plt.rcParams['font.family'] = 'sans-serif'
95
+ plt.rcParams['font.sans-serif'] = [font_name]
96
+ plt.rcParams['axes.unicode_minus'] = False
97
+ font_kwargs = {'fontproperties': font_prop}
98
+ print(f"成功加载字体: {font_name}")
99
+ except Exception as e:
100
+ print(f"加载指定字体失败: {e}")
101
+ # 尝试使用系统字体
102
+ try:
103
+ plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
104
+ plt.rcParams['axes.unicode_minus'] = False
105
+ except:
106
+ pass
107
+ else:
108
+ print(f"警告: 字体文件不存在: {font_path}")
109
+ try:
110
+ plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
111
+ plt.rcParams['axes.unicode_minus'] = False
112
+ except:
113
+ pass
114
+ plt.figure(figsize=(20, 10), dpi=100)
115
+ ax = plt.axes(projection=ccrs.PlateCarree())
116
+ ax.add_feature(cfeature.LAND, facecolor='none') # 陆地无色
117
+ ax.add_feature(cfeature.OCEAN, facecolor='none') # 海洋无色
118
+ ax.add_feature(cfeature.COASTLINE, linewidth=0.8, edgecolor='black') # 海岸线黑色
119
+ ax.add_feature(cfeature.BORDERS, linestyle='-', linewidth=0.5, edgecolor='black') # 国界线黑色
120
+ ax.add_feature(cfeature.LAKES, alpha=0.3, facecolor='none', edgecolor='gray') # 湖泊无色,灰色边界
121
+ ax.add_feature(cfeature.RIVERS, edgecolor='gray', linewidth=0.5) # 河流灰色
122
+ lon_grid, lat_grid = np.meshgrid(lonArr1, latArr1)
123
+ stride = 10 # 每10个点取1个
124
+ cmap = {
125
+ "radar": cmp_hjnwtx["radar_nmc"],
126
+ "pre": cmp_hjnwtx["pre_tqw"],
127
+ None: 'summer'
128
+ }.get(ty)
129
+ minmax = {
130
+ "radar": [0,80],
131
+ "pre": [0,20],
132
+ None: [np.nanmin(b),np.nanmax(b)]
133
+ }.get(ty)
134
+
135
+ setlabel = {
136
+ "radar": '雷达组合反射率\n单位:(dbz)',
137
+ "pre": '降雨量\n单位:(mm)',
138
+ None: '数据'
139
+ }.get(ty)
140
+ img = ax.pcolormesh(lon_grid[::stride, ::stride],
141
+ lat_grid[::stride, ::stride],
142
+ b[::stride, ::stride],
143
+ cmap=cmap,
144
+ shading='auto',
145
+ transform=ccrs.PlateCarree(), vmin=minmax[0], vmax=minmax[1])
146
+ cbar = plt.colorbar(img, ax=ax, orientation='vertical', pad=0.05, shrink=0.6)
147
+ if font_kwargs:
148
+ cbar.set_label(setlabel, fontsize=12, **font_kwargs)
149
+ ax.set_xticks(np.arange(-180, 181, 30), crs=ccrs.PlateCarree())
150
+ ax.set_yticks(np.arange(-90, 91, 15), crs=ccrs.PlateCarree())
151
+ ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True))
152
+ ax.yaxis.set_major_formatter(LatitudeFormatter())
153
+ ax.gridlines(color='gray', linestyle=':', alpha=0.5)
154
+ ax.set_title(title, fontsize=16, pad=20)
155
+ ax.set_global()
156
+ plt.tight_layout()
157
+ os.makedirs(saveDir, exist_ok=True)
158
+ plt.savefig(f"./{saveDir}/plotScatter_glob{now_str}_{ty}_{name}.png", dpi=300, bbox_inches="tight")
159
+ plt.close()
160
+
161
+ '''
162
+ plotGlobal(satH9[0], latArrsatH9, lonArrsatH9, title=f'全球气象雷达组合反射率分布图',saveDir="./plotGlobal", ty="radar",name = "")
163
+ '''
164
+
57
165
  import datetime
58
166
  import numpy as np
59
167
  import matplotlib.pyplot as plt
@@ -89,16 +197,31 @@ def plotGlobalPlus(b, latArr1, lonArr1, cmap='summer', title='Global QPF Data Vi
89
197
  cmap = {
90
198
  "radar": cmp_hjnwtx["radar_nmc"],
91
199
  "pre": cmp_hjnwtx["pre_tqw"],
92
- None: cmap
93
- }.get(ty, cmap)
200
+ None: 'summer'
201
+ }.get(ty)
202
+
203
+ minmax = {
204
+ "radar": [0,80],
205
+ "pre": [0,20],
206
+ None: [np.nanmin(b),np.nanmax(b)]
207
+ }.get(ty)
208
+
209
+ setlabel = {
210
+ "radar": 'Composite Reflectivity (Radar)\nUnit: (dBZ)',
211
+ "pre": 'Precipitation\nUnit: (mm)',
212
+ None: 'Data'
213
+ }.get(ty)
214
+
94
215
  img = ax.pcolormesh(lon_grid[::stride, ::stride],
95
216
  lat_grid[::stride, ::stride],
96
217
  b[::stride, ::stride],
97
218
  cmap=cmap,
98
219
  shading='auto',
220
+ vmin = minmax[0],
221
+ vmax = minmax[1],
99
222
  transform=ccrs.PlateCarree())
100
223
  cbar = plt.colorbar(img, ax=ax, orientation='vertical', pad=0.05, shrink=0.6)
101
- cbar.set_label('Value Scale', fontsize=12)
224
+ cbar.set_label(setlabel , fontsize=12)
102
225
  ax.set_xticks(np.arange(-180, 181, 30), crs=ccrs.PlateCarree())
103
226
  ax.set_yticks(np.arange(-90, 91, 15), crs=ccrs.PlateCarree())
104
227
  ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True))
@@ -113,6 +236,7 @@ def plotGlobalPlus(b, latArr1, lonArr1, cmap='summer', title='Global QPF Data Vi
113
236
  plt.close()
114
237
  print(f"图像已保存到: {save_path}")
115
238
  return save_path
239
+
116
240
  """
117
241
  if __name__ == "__main__":
118
242
  plotGlobal(
@@ -126,6 +250,7 @@ if __name__ == "__main__":
126
250
  )
127
251
  """
128
252
 
253
+
129
254
  import ssl
130
255
  import urllib.request
131
256
  ssl._create_default_https_context = ssl._create_unverified_context
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shancx
3
- Version: 1.9.33.219
3
+ Version: 1.9.33.222
4
4
  Summary: A simple timer decorator
5
5
  Home-page: https://gitee.com/shancx
6
6
  Author: shancx
@@ -66,12 +66,13 @@ shancx/H9/geometry.py,sha256=ZoCfgP07ANqDxyLf8uFN016DPl7QqW9pAV3sr2ekCng,95893
66
66
  shancx/Hug/__init__.py,sha256=NvcqXM0CSwXYtTr5yj4zfkag_7PZcI5tCsIHjuLNXTQ,3040
67
67
  shancx/Mos/__init__.py,sha256=IDlCLNN6a_mguYmRcAPcevHSDaud5ZhvYNSuASqztcE,1563
68
68
  shancx/NN/__init__.py,sha256=ENgZxIzUJzkuxArkcH-1JlxQA08Urq2ppFkGCbIURZk,9219
69
+ shancx/NN/chainMul.py,sha256=p7q_jrgFQkkfAYr_ZJFirwZOYoyn31QOVYERwhBGH4k,8649
69
70
  shancx/Plot/GlobMap.py,sha256=WRvZOf5bo8IfECk1-sN4g6K0CrcJhSoEJAiLvZAWDwg,13021
70
71
  shancx/Plot/Gray2RGB.py,sha256=yDXu1xWVi7OtrS8_ExxK_ev1988kj1ZxoNCWf-kl4Zc,2734
71
72
  shancx/Plot/__init__.py,sha256=_fmDFZfh9HzDPBPKCMPrDT2DsblLVfrO-uFvUg76a74,19194
72
73
  shancx/Plot/draw_day_CR_PNG.py,sha256=ftOYdk80Xmry_H1uaypjrTUA0mJZBV7EGt5T7JfVg0E,7267
73
74
  shancx/Plot/exam.py,sha256=XXyBQp1Eb1siNiu7FY8ACiWH0g43ZSLTOGLqs3aKomE,3966
74
- shancx/Plot/plotGlobal.py,sha256=B2887VhMop6B3jEg7zD7ADlyIbKfyUOKffSJ2oEmEbo,15270
75
+ shancx/Plot/plotGlobal.py,sha256=X06RvuTDqX9S1WUx_mZ_u7RJ96w1HWk_ca5N47YZfo0,20367
75
76
  shancx/Plot/radarNmc.py,sha256=ixmoDaoT6whmmrv4wD4p7H_DiNsyOEb2tUoz2KQgDeM,1273
76
77
  shancx/Plot/single_china_map.py,sha256=cRmZW6TtLBwLb-Y3syim_K1jM350CmB5zkK1nrAcaRQ,2116
77
78
  shancx/RdPzl/__init__.py,sha256=I5Isz3KfDgFZAdlRk4D-Hvp-8xH4F2Dl0XGxYGzUcKc,1166
@@ -86,7 +87,7 @@ shancx/Train/multiGpu.py,sha256=D_oZeiSc7VWktpnVDwrFOC1CYZSt9rxOKY5lngE5vFg,820
86
87
  shancx/Train/prepare.py,sha256=vL_8UOA66oZCBIwCICtihsGibivtNgaVJGulJxfNdn8,6793
87
88
  shancx/Train/renet50.py,sha256=wEhYk1X96WE5zuqHqVxWLJa-A5jDNkz4z6edORNufnA,6428
88
89
  shancx/tensBoard/__init__.py,sha256=ga2C5YyJITvvQA1ocpxna_KNFnNRJVwkTjLoIglLZUQ,993
89
- shancx-1.9.33.219.dist-info/METADATA,sha256=1kSsnmfca6bBuHc__iWVuMBQJ_71kxk7fHHwyQNssaY,850
90
- shancx-1.9.33.219.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
- shancx-1.9.33.219.dist-info/top_level.txt,sha256=akfCS1vKWz3pNmEN_yN9ZiGp-60IQY5ET38mRx_i_-4,7
92
- shancx-1.9.33.219.dist-info/RECORD,,
90
+ shancx-1.9.33.222.dist-info/METADATA,sha256=vnbm-h0oqRzFukBJQK-CJTJxGCY7DbC1mOmEZ9LO0-I,850
91
+ shancx-1.9.33.222.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
92
+ shancx-1.9.33.222.dist-info/top_level.txt,sha256=akfCS1vKWz3pNmEN_yN9ZiGp-60IQY5ET38mRx_i_-4,7
93
+ shancx-1.9.33.222.dist-info/RECORD,,