pixelarraylib 1.0.0__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.
- arraylib/__init__.py +36 -0
- arraylib/__main__.py +126 -0
- arraylib/aliyun/__init__.py +0 -0
- arraylib/aliyun/aliyun_email.py +130 -0
- arraylib/aliyun/billing.py +477 -0
- arraylib/aliyun/content_scanner.py +253 -0
- arraylib/aliyun/domain.py +434 -0
- arraylib/aliyun/eci.py +47 -0
- arraylib/aliyun/ecs.py +68 -0
- arraylib/aliyun/fc.py +142 -0
- arraylib/aliyun/oss.py +649 -0
- arraylib/aliyun/sms.py +59 -0
- arraylib/aliyun/sts.py +124 -0
- arraylib/db_utils/mysql.py +544 -0
- arraylib/db_utils/redis.py +373 -0
- arraylib/decorators/__init__.py +13 -0
- arraylib/decorators/decorators.py +194 -0
- arraylib/gitlab/__init__.py +0 -0
- arraylib/gitlab/code_analyzer.py +344 -0
- arraylib/gitlab/pypi_package_manager.py +61 -0
- arraylib/monitor/__init__.py +0 -0
- arraylib/monitor/feishu.py +132 -0
- arraylib/net/request.py +143 -0
- arraylib/scripts/__init__.py +22 -0
- arraylib/scripts/collect_code_to_txt.py +327 -0
- arraylib/scripts/create_test_case_files.py +100 -0
- arraylib/scripts/nginx_proxy_to_ecs.py +119 -0
- arraylib/scripts/remove_empty_lines.py +120 -0
- arraylib/scripts/summary_code_count.py +430 -0
- arraylib/system/__init__.py +0 -0
- arraylib/system/common.py +390 -0
- pixelarraylib-1.0.0.dist-info/METADATA +141 -0
- pixelarraylib-1.0.0.dist-info/RECORD +37 -0
- pixelarraylib-1.0.0.dist-info/WHEEL +5 -0
- pixelarraylib-1.0.0.dist-info/entry_points.txt +2 -0
- pixelarraylib-1.0.0.dist-info/licenses/LICENSE +21 -0
- pixelarraylib-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
from typing import List
|
|
3
|
+
import redis
|
|
4
|
+
import redis.asyncio as aioredis
|
|
5
|
+
from arraylib.monitor.feishu import Feishu
|
|
6
|
+
|
|
7
|
+
feishu_alert = Feishu("devtoolkit服务报警")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RedisUtils:
|
|
11
|
+
def __init__(self, host, port, password, db):
|
|
12
|
+
self.redis_client = redis.Redis(
|
|
13
|
+
host=host,
|
|
14
|
+
port=port,
|
|
15
|
+
password=password,
|
|
16
|
+
db=db,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def get_redis_client(self):
|
|
20
|
+
return self.redis_client
|
|
21
|
+
|
|
22
|
+
def set(self, key, value, expire_seconds=None):
|
|
23
|
+
"""
|
|
24
|
+
description:
|
|
25
|
+
设置缓存
|
|
26
|
+
parameters:
|
|
27
|
+
key(str): 缓存键
|
|
28
|
+
value(str): 缓存值
|
|
29
|
+
expire_seconds(int): 缓存过期时间
|
|
30
|
+
return:
|
|
31
|
+
flag(bool): 是否设置成功
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
self.redis_client.set(key, value, ex=expire_seconds)
|
|
35
|
+
return True
|
|
36
|
+
except Exception as e:
|
|
37
|
+
feishu_alert.send(traceback.format_exc())
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
def get(self, key, default_value=""):
|
|
41
|
+
"""
|
|
42
|
+
description:
|
|
43
|
+
获取缓存
|
|
44
|
+
parameters:
|
|
45
|
+
key(str): 缓存键
|
|
46
|
+
default_value(str): 默认值
|
|
47
|
+
return:
|
|
48
|
+
value(str): 缓存值
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
value = self.redis_client.get(key)
|
|
52
|
+
if value is None:
|
|
53
|
+
return default_value
|
|
54
|
+
return value.decode()
|
|
55
|
+
except Exception as e:
|
|
56
|
+
feishu_alert.send(traceback.format_exc())
|
|
57
|
+
return default_value
|
|
58
|
+
|
|
59
|
+
def delete(self, key):
|
|
60
|
+
"""
|
|
61
|
+
description:
|
|
62
|
+
删除缓存
|
|
63
|
+
parameters:
|
|
64
|
+
key(str): 缓存键
|
|
65
|
+
return:
|
|
66
|
+
flag(bool): 是否删除成功
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
self.redis_client.delete(key)
|
|
70
|
+
return True
|
|
71
|
+
except Exception as e:
|
|
72
|
+
feishu_alert.send(traceback.format_exc())
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
def delete_many(self, keys: List[str]) -> bool:
|
|
76
|
+
"""
|
|
77
|
+
description:
|
|
78
|
+
删除多个缓存
|
|
79
|
+
parameters:
|
|
80
|
+
keys(list): 缓存键列表
|
|
81
|
+
return:
|
|
82
|
+
flag(bool): 是否删除成功
|
|
83
|
+
"""
|
|
84
|
+
try:
|
|
85
|
+
self.redis_client.delete(*keys)
|
|
86
|
+
return True
|
|
87
|
+
except Exception as e:
|
|
88
|
+
feishu_alert.send(traceback.format_exc())
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
def set_hash(self, key, field, value, expire_seconds=None):
|
|
92
|
+
"""
|
|
93
|
+
description:
|
|
94
|
+
设置哈希表
|
|
95
|
+
parameters:
|
|
96
|
+
key(str): 哈希表键
|
|
97
|
+
field(str): 哈希表字段
|
|
98
|
+
value(str): 哈希表值
|
|
99
|
+
expire_seconds(int, optional): 哈希表过期时间(秒),默认为None表示不过期
|
|
100
|
+
return:
|
|
101
|
+
flag(bool): 是否设置成功
|
|
102
|
+
"""
|
|
103
|
+
try:
|
|
104
|
+
self.redis_client.hset(key, field, value)
|
|
105
|
+
if expire_seconds is not None:
|
|
106
|
+
self.redis_client.expire(key, expire_seconds)
|
|
107
|
+
return True
|
|
108
|
+
except Exception as e:
|
|
109
|
+
feishu_alert.send(traceback.format_exc())
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
def get_hash(self, key, field):
|
|
113
|
+
"""
|
|
114
|
+
description:
|
|
115
|
+
获取哈希表的值
|
|
116
|
+
parameters:
|
|
117
|
+
key(str): 哈希表键
|
|
118
|
+
field(str): 哈希表字段
|
|
119
|
+
return:
|
|
120
|
+
value(str): 哈希表值
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
value = self.redis_client.hget(key, field)
|
|
124
|
+
if value is None:
|
|
125
|
+
return ""
|
|
126
|
+
return value.decode()
|
|
127
|
+
except Exception as e:
|
|
128
|
+
feishu_alert.send(traceback.format_exc())
|
|
129
|
+
return ""
|
|
130
|
+
|
|
131
|
+
def delete_hash(self, key, field):
|
|
132
|
+
"""
|
|
133
|
+
description:
|
|
134
|
+
删除哈希表的值
|
|
135
|
+
parameters:
|
|
136
|
+
key(str): 哈希表键
|
|
137
|
+
field(str): 哈希表字段
|
|
138
|
+
return:
|
|
139
|
+
flag(bool): 是否删除成功
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
self.redis_client.hdel(key, field)
|
|
143
|
+
return True
|
|
144
|
+
except Exception as e:
|
|
145
|
+
feishu_alert.send(traceback.format_exc())
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
def list_hash_keys(self, key):
|
|
149
|
+
"""
|
|
150
|
+
description:
|
|
151
|
+
获取哈希表的所有键
|
|
152
|
+
parameters:
|
|
153
|
+
key(str): 哈希表键
|
|
154
|
+
return:
|
|
155
|
+
keys(list): 哈希表的键
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
return [key.decode() for key in self.redis_client.hkeys(key)]
|
|
159
|
+
except Exception as e:
|
|
160
|
+
feishu_alert.send(traceback.format_exc())
|
|
161
|
+
return []
|
|
162
|
+
|
|
163
|
+
def list_keys(self, prefix=""):
|
|
164
|
+
"""
|
|
165
|
+
description:
|
|
166
|
+
获取所有以指定前缀开头的键
|
|
167
|
+
parameters:
|
|
168
|
+
prefix(str): 键前缀,默认为空字符串,表示获取所有键
|
|
169
|
+
return:
|
|
170
|
+
keys(list): 键列表
|
|
171
|
+
"""
|
|
172
|
+
try:
|
|
173
|
+
# 使用 Redis 的 scan 方法替代 keys,避免大数据量时阻塞
|
|
174
|
+
cursor = 0
|
|
175
|
+
keys = []
|
|
176
|
+
pattern = f"{prefix}*" if prefix else "*"
|
|
177
|
+
while True:
|
|
178
|
+
cursor, batch = self.redis_client.scan(
|
|
179
|
+
cursor=cursor, match=pattern, count=1000
|
|
180
|
+
)
|
|
181
|
+
keys.extend(batch)
|
|
182
|
+
if cursor == 0:
|
|
183
|
+
break
|
|
184
|
+
return [key.decode() for key in keys]
|
|
185
|
+
except Exception as e:
|
|
186
|
+
feishu_alert.send(traceback.format_exc())
|
|
187
|
+
return []
|
|
188
|
+
|
|
189
|
+
def __del__(self):
|
|
190
|
+
self.redis_client.close()
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class RedisUtilsAsync:
|
|
194
|
+
def __init__(self, host, port, password, db):
|
|
195
|
+
self.async_redis_client = aioredis.from_url(
|
|
196
|
+
f"redis://:{password}@{host}:{port}/{db}"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
async def get_async_redis_client(self):
|
|
200
|
+
return self.async_redis_client
|
|
201
|
+
|
|
202
|
+
async def set(self, key, value, expire_seconds=None):
|
|
203
|
+
"""
|
|
204
|
+
description:
|
|
205
|
+
异步设置缓存
|
|
206
|
+
parameters:
|
|
207
|
+
key(str): 缓存键
|
|
208
|
+
value(str): 缓存值
|
|
209
|
+
expire_seconds(int): 缓存过期时间
|
|
210
|
+
return:
|
|
211
|
+
flag(bool): 是否设置成功
|
|
212
|
+
"""
|
|
213
|
+
try:
|
|
214
|
+
await self.async_redis_client.set(key, value, ex=expire_seconds)
|
|
215
|
+
return True
|
|
216
|
+
except Exception as e:
|
|
217
|
+
feishu_alert.send(traceback.format_exc())
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
async def get(self, key, default_value=""):
|
|
221
|
+
"""
|
|
222
|
+
description:
|
|
223
|
+
异步获取缓存
|
|
224
|
+
parameters:
|
|
225
|
+
key(str): 缓存键
|
|
226
|
+
default_value(str): 默认值
|
|
227
|
+
return:
|
|
228
|
+
value(str): 缓存值
|
|
229
|
+
"""
|
|
230
|
+
try:
|
|
231
|
+
value = await self.async_redis_client.get(key)
|
|
232
|
+
if value is None:
|
|
233
|
+
return default_value
|
|
234
|
+
return value.decode()
|
|
235
|
+
except Exception as e:
|
|
236
|
+
feishu_alert.send(traceback.format_exc())
|
|
237
|
+
return default_value
|
|
238
|
+
|
|
239
|
+
async def delete(self, key):
|
|
240
|
+
"""
|
|
241
|
+
description:
|
|
242
|
+
异步删除缓存
|
|
243
|
+
parameters:
|
|
244
|
+
key(str): 缓存键
|
|
245
|
+
return:
|
|
246
|
+
flag(bool): 是否删除成功
|
|
247
|
+
"""
|
|
248
|
+
try:
|
|
249
|
+
await self.async_redis_client.delete(key)
|
|
250
|
+
return True
|
|
251
|
+
except Exception as e:
|
|
252
|
+
feishu_alert.send(traceback.format_exc())
|
|
253
|
+
return False
|
|
254
|
+
|
|
255
|
+
async def delete_many(self, keys: List[str]) -> bool:
|
|
256
|
+
"""
|
|
257
|
+
description:
|
|
258
|
+
异步删除多个缓存
|
|
259
|
+
parameters:
|
|
260
|
+
keys(list): 缓存键列表
|
|
261
|
+
return:
|
|
262
|
+
flag(bool): 是否删除成功
|
|
263
|
+
"""
|
|
264
|
+
try:
|
|
265
|
+
await self.async_redis_client.delete(*keys)
|
|
266
|
+
return True
|
|
267
|
+
except Exception as e:
|
|
268
|
+
feishu_alert.send(traceback.format_exc())
|
|
269
|
+
return False
|
|
270
|
+
|
|
271
|
+
async def set_hash(self, key, field, value, expire_seconds=None):
|
|
272
|
+
"""
|
|
273
|
+
description:
|
|
274
|
+
异步设置哈希表
|
|
275
|
+
parameters:
|
|
276
|
+
key(str): 哈希表键
|
|
277
|
+
field(str): 哈希表字段
|
|
278
|
+
value(str): 哈希表值
|
|
279
|
+
expire_seconds(int, optional): 哈希表过期时间(秒),默认为None表示不过期
|
|
280
|
+
return:
|
|
281
|
+
flag(bool): 是否设置成功
|
|
282
|
+
"""
|
|
283
|
+
try:
|
|
284
|
+
await self.async_redis_client.hset(key, field, value)
|
|
285
|
+
if expire_seconds is not None:
|
|
286
|
+
await self.async_redis_client.expire(key, expire_seconds)
|
|
287
|
+
return True
|
|
288
|
+
except Exception as e:
|
|
289
|
+
feishu_alert.send(traceback.format_exc())
|
|
290
|
+
return False
|
|
291
|
+
|
|
292
|
+
async def get_hash(self, key, field):
|
|
293
|
+
"""
|
|
294
|
+
description:
|
|
295
|
+
异步获取哈希表的值
|
|
296
|
+
parameters:
|
|
297
|
+
key(str): 哈希表键
|
|
298
|
+
field(str): 哈希表字段
|
|
299
|
+
return:
|
|
300
|
+
value(str): 哈希表值
|
|
301
|
+
"""
|
|
302
|
+
try:
|
|
303
|
+
value = await self.async_redis_client.hget(key, field)
|
|
304
|
+
if value is None:
|
|
305
|
+
return ""
|
|
306
|
+
return value.decode()
|
|
307
|
+
except Exception as e:
|
|
308
|
+
feishu_alert.send(traceback.format_exc())
|
|
309
|
+
return ""
|
|
310
|
+
|
|
311
|
+
async def delete_hash(self, key, field):
|
|
312
|
+
"""
|
|
313
|
+
description:
|
|
314
|
+
异步删除哈希表的值
|
|
315
|
+
parameters:
|
|
316
|
+
key(str): 哈希表键
|
|
317
|
+
field(str): 哈希表字段
|
|
318
|
+
return:
|
|
319
|
+
flag(bool): 是否删除成功
|
|
320
|
+
"""
|
|
321
|
+
try:
|
|
322
|
+
await self.async_redis_client.hdel(key, field)
|
|
323
|
+
return True
|
|
324
|
+
except Exception as e:
|
|
325
|
+
feishu_alert.send(traceback.format_exc())
|
|
326
|
+
return False
|
|
327
|
+
|
|
328
|
+
async def list_hash_keys(self, key):
|
|
329
|
+
"""
|
|
330
|
+
description:
|
|
331
|
+
异步获取哈希表的所有键
|
|
332
|
+
parameters:
|
|
333
|
+
key(str): 哈希表键
|
|
334
|
+
return:
|
|
335
|
+
keys(list): 哈希表的键
|
|
336
|
+
"""
|
|
337
|
+
try:
|
|
338
|
+
keys = await self.async_redis_client.hkeys(key)
|
|
339
|
+
return [key.decode() for key in keys]
|
|
340
|
+
except Exception as e:
|
|
341
|
+
feishu_alert.send(traceback.format_exc())
|
|
342
|
+
return []
|
|
343
|
+
|
|
344
|
+
async def list_keys(self, prefix=""):
|
|
345
|
+
"""
|
|
346
|
+
description:
|
|
347
|
+
异步获取所有以指定前缀开头的键
|
|
348
|
+
parameters:
|
|
349
|
+
prefix(str): 键前缀,默认为空字符串,表示获取所有键
|
|
350
|
+
return:
|
|
351
|
+
keys(list): 键列表
|
|
352
|
+
"""
|
|
353
|
+
try:
|
|
354
|
+
# 使用 Redis 的 scan 方法替代 keys,避免大数据量时阻塞
|
|
355
|
+
cursor = 0
|
|
356
|
+
keys = []
|
|
357
|
+
pattern = f"{prefix}*" if prefix else "*"
|
|
358
|
+
while True:
|
|
359
|
+
cursor, batch = await self.async_redis_client.scan(
|
|
360
|
+
cursor=cursor, match=pattern, count=1000
|
|
361
|
+
)
|
|
362
|
+
keys.extend(batch)
|
|
363
|
+
if cursor == 0:
|
|
364
|
+
break
|
|
365
|
+
return [key.decode() for key in keys]
|
|
366
|
+
except Exception as e:
|
|
367
|
+
feishu_alert.send(traceback.format_exc())
|
|
368
|
+
return []
|
|
369
|
+
|
|
370
|
+
async def close(self):
|
|
371
|
+
"""关闭异步Redis连接"""
|
|
372
|
+
if self.async_redis_client:
|
|
373
|
+
await self.async_redis_client.close()
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
import shutil
|
|
5
|
+
import traceback
|
|
6
|
+
import asyncio
|
|
7
|
+
from typing import Callable, Any
|
|
8
|
+
from time import sleep
|
|
9
|
+
from functools import wraps
|
|
10
|
+
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
|
11
|
+
from arraylib.monitor.feishu import Feishu
|
|
12
|
+
import inspect
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def catch_exception(
|
|
16
|
+
exception_return: Any = None,
|
|
17
|
+
alert_params: bool = True,
|
|
18
|
+
addtional_alert: str = "",
|
|
19
|
+
alert_channel: str = "devtoolkit服务报警",
|
|
20
|
+
):
|
|
21
|
+
feishu_alert = Feishu(alert_channel)
|
|
22
|
+
def get_caller_function_name():
|
|
23
|
+
"""
|
|
24
|
+
description:
|
|
25
|
+
获取调用当前函数的函数名
|
|
26
|
+
return:
|
|
27
|
+
str: 函数名
|
|
28
|
+
"""
|
|
29
|
+
return inspect.getframeinfo(inspect.currentframe().f_back.f_back).function
|
|
30
|
+
|
|
31
|
+
def decorator(func: Callable) -> Callable:
|
|
32
|
+
@wraps(func)
|
|
33
|
+
def sync_wrapper(*args, **kwargs) -> Any:
|
|
34
|
+
try:
|
|
35
|
+
return func(*args, **kwargs)
|
|
36
|
+
except Exception as e:
|
|
37
|
+
alert_params_str = f"参数:{args, kwargs}" if alert_params else ""
|
|
38
|
+
alert_message = f"文件{os.path.relpath(inspect.getfile(func))}中的函数{get_caller_function_name()}执行失败,{alert_params_str},错误信息如下:\n {traceback.format_exc()}"
|
|
39
|
+
if addtional_alert:
|
|
40
|
+
alert_message += f"\n{addtional_alert}"
|
|
41
|
+
feishu_alert.send(alert_message)
|
|
42
|
+
return exception_return
|
|
43
|
+
|
|
44
|
+
@wraps(func)
|
|
45
|
+
async def async_wrapper(*args, **kwargs) -> Any:
|
|
46
|
+
try:
|
|
47
|
+
return await func(*args, **kwargs)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
alert_params_str = f"参数:{args, kwargs}" if alert_params else ""
|
|
50
|
+
alert_message = f"文件{os.path.relpath(inspect.getfile(func))}中的函数{get_caller_function_name()}执行失败,{alert_params_str},错误信息如下:\n {traceback.format_exc()}"
|
|
51
|
+
if addtional_alert:
|
|
52
|
+
alert_message += f"\n{addtional_alert}"
|
|
53
|
+
feishu_alert.send(alert_message)
|
|
54
|
+
return exception_return
|
|
55
|
+
|
|
56
|
+
if asyncio.iscoroutinefunction(func):
|
|
57
|
+
return async_wrapper
|
|
58
|
+
else:
|
|
59
|
+
return sync_wrapper
|
|
60
|
+
|
|
61
|
+
return decorator
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def with_retry(
|
|
65
|
+
retry_times: int = 3,
|
|
66
|
+
retry_interval: int = 1,
|
|
67
|
+
) -> Callable:
|
|
68
|
+
def decorator(func: Callable) -> Callable:
|
|
69
|
+
@functools.wraps(func)
|
|
70
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
71
|
+
for attempt in range(retry_times):
|
|
72
|
+
try:
|
|
73
|
+
return func(*args, **kwargs)
|
|
74
|
+
except Exception as e:
|
|
75
|
+
if attempt < retry_times - 1:
|
|
76
|
+
print(f"第{attempt + 1}次尝试失败,{retry_interval}秒后重试...")
|
|
77
|
+
sleep(retry_interval)
|
|
78
|
+
else:
|
|
79
|
+
print(f"操作失败,已重试{retry_times}次,执行失败")
|
|
80
|
+
raise e
|
|
81
|
+
|
|
82
|
+
return wrapper
|
|
83
|
+
|
|
84
|
+
return decorator
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def with_timeout(seconds):
|
|
88
|
+
def decorator(func):
|
|
89
|
+
@wraps(func)
|
|
90
|
+
def wrapper(*args, **kwargs):
|
|
91
|
+
with ThreadPoolExecutor(max_workers=1) as executor:
|
|
92
|
+
future = executor.submit(func, *args, **kwargs)
|
|
93
|
+
try:
|
|
94
|
+
return future.result(timeout=seconds)
|
|
95
|
+
except TimeoutError:
|
|
96
|
+
raise TimeoutError(
|
|
97
|
+
f"Function {func.__name__} timed out after {seconds} seconds"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return wrapper
|
|
101
|
+
|
|
102
|
+
return decorator
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def avoid_chinese_filename(func):
|
|
106
|
+
def contains_chinese(text):
|
|
107
|
+
if not text:
|
|
108
|
+
return False
|
|
109
|
+
chinese_pattern = re.compile(r"[\u4e00-\u9fff]")
|
|
110
|
+
return bool(chinese_pattern.search(text))
|
|
111
|
+
|
|
112
|
+
def create_temp_path(original_path):
|
|
113
|
+
if not contains_chinese(original_path):
|
|
114
|
+
return original_path
|
|
115
|
+
|
|
116
|
+
dir_path = os.path.dirname(original_path)
|
|
117
|
+
filename = os.path.basename(original_path)
|
|
118
|
+
name, ext = os.path.splitext(filename)
|
|
119
|
+
|
|
120
|
+
import uuid
|
|
121
|
+
|
|
122
|
+
temp_name = f"temp_{uuid.uuid4().hex[:8]}{ext}"
|
|
123
|
+
temp_path = os.path.join(dir_path, temp_name)
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
shutil.copy2(original_path, temp_path)
|
|
127
|
+
return temp_path
|
|
128
|
+
except Exception as e:
|
|
129
|
+
return original_path
|
|
130
|
+
|
|
131
|
+
def restore_original_files(path_mapping):
|
|
132
|
+
for temp_path, original_path in path_mapping.items():
|
|
133
|
+
try:
|
|
134
|
+
if os.path.exists(temp_path):
|
|
135
|
+
os.makedirs(os.path.dirname(original_path), exist_ok=True)
|
|
136
|
+
|
|
137
|
+
if not os.path.exists(original_path):
|
|
138
|
+
os.rename(temp_path, original_path)
|
|
139
|
+
else:
|
|
140
|
+
os.remove(original_path)
|
|
141
|
+
os.rename(temp_path, original_path)
|
|
142
|
+
except Exception as e:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
def cleanup_temp_files(temp_files):
|
|
146
|
+
for temp_path in temp_files:
|
|
147
|
+
try:
|
|
148
|
+
if os.path.exists(temp_path):
|
|
149
|
+
os.remove(temp_path)
|
|
150
|
+
except Exception as e:
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
def wrapper(*args, **kwargs):
|
|
154
|
+
path_mapping = {}
|
|
155
|
+
temp_files = []
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
new_args = list(args)
|
|
159
|
+
for i, arg in enumerate(args):
|
|
160
|
+
if isinstance(arg, str):
|
|
161
|
+
is_file_path = os.path.exists(arg)
|
|
162
|
+
if is_file_path:
|
|
163
|
+
temp_path = create_temp_path(arg)
|
|
164
|
+
if temp_path != arg:
|
|
165
|
+
path_mapping[temp_path] = arg
|
|
166
|
+
new_args[i] = temp_path
|
|
167
|
+
temp_files.append(temp_path)
|
|
168
|
+
|
|
169
|
+
new_kwargs = kwargs.copy()
|
|
170
|
+
for key, value in kwargs.items():
|
|
171
|
+
if isinstance(value, str):
|
|
172
|
+
if os.path.exists(value):
|
|
173
|
+
temp_path = create_temp_path(value)
|
|
174
|
+
if temp_path != value:
|
|
175
|
+
path_mapping[temp_path] = value
|
|
176
|
+
new_kwargs[key] = temp_path
|
|
177
|
+
temp_files.append(temp_path)
|
|
178
|
+
|
|
179
|
+
result = func(*new_args, **new_kwargs)
|
|
180
|
+
|
|
181
|
+
restore_original_files(path_mapping)
|
|
182
|
+
|
|
183
|
+
return result
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
try:
|
|
187
|
+
restore_original_files(path_mapping)
|
|
188
|
+
except:
|
|
189
|
+
pass
|
|
190
|
+
raise e
|
|
191
|
+
finally:
|
|
192
|
+
cleanup_temp_files(temp_files)
|
|
193
|
+
|
|
194
|
+
return wrapper
|
|
File without changes
|