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,390 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
import subprocess
|
|
5
|
+
import traceback
|
|
6
|
+
from typing import Union, List, Generator
|
|
7
|
+
from cryptography.fernet import Fernet
|
|
8
|
+
import base64
|
|
9
|
+
from arraylib.monitor.feishu import Feishu
|
|
10
|
+
import os
|
|
11
|
+
import paramiko
|
|
12
|
+
|
|
13
|
+
feishu_alert = Feishu("devtoolkit服务报警")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
async def execute_batch_async_tasks(tasks, semaphore_count=None):
|
|
17
|
+
if semaphore_count is None:
|
|
18
|
+
return await asyncio.gather(*tasks)
|
|
19
|
+
|
|
20
|
+
semaphore = asyncio.Semaphore(semaphore_count)
|
|
21
|
+
|
|
22
|
+
async def sem_task(task):
|
|
23
|
+
async with semaphore:
|
|
24
|
+
return await task
|
|
25
|
+
|
|
26
|
+
return await asyncio.gather(*(sem_task(task) for task in tasks))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def encode_chinese_string(text: str) -> str:
|
|
30
|
+
"""
|
|
31
|
+
description:
|
|
32
|
+
将中文转换为UTF-8编码的字符串
|
|
33
|
+
parameters:
|
|
34
|
+
text(str): 需要转换的字符串
|
|
35
|
+
return:
|
|
36
|
+
converted_text(str): 转换后的字符串(URL安全的base64格式)
|
|
37
|
+
"""
|
|
38
|
+
# 使用URL安全的base64编码方法
|
|
39
|
+
return base64.urlsafe_b64encode(text.encode("utf-8")).decode("ascii").rstrip("=")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def decode_chinese_string(encoded_text: str) -> str:
|
|
43
|
+
"""
|
|
44
|
+
description:
|
|
45
|
+
将UTF-8编码的字符串转换为中文
|
|
46
|
+
parameters:
|
|
47
|
+
encoded_text(str): 编码后的字符串(URL安全的base64格式)
|
|
48
|
+
return:
|
|
49
|
+
text(str): 原始中文字符串
|
|
50
|
+
"""
|
|
51
|
+
# 添加回可能被移除的填充字符'='
|
|
52
|
+
padding = 4 - (len(encoded_text) % 4)
|
|
53
|
+
encoded_text += "=" * padding
|
|
54
|
+
# 使用URL安全的base64解码方法
|
|
55
|
+
return base64.urlsafe_b64decode(encoded_text.encode("ascii")).decode("utf-8")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def generate_fernet_key() -> bytes:
|
|
59
|
+
"""
|
|
60
|
+
description:
|
|
61
|
+
生成Fernet加密密钥
|
|
62
|
+
return:
|
|
63
|
+
key(str): 加密密钥
|
|
64
|
+
"""
|
|
65
|
+
return Fernet.generate_key().decode()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def encrypt_string(text: str, key: str) -> tuple[str, bytes]:
|
|
69
|
+
"""
|
|
70
|
+
description:
|
|
71
|
+
使用Fernet对称加密算法加密字符串
|
|
72
|
+
parameters:
|
|
73
|
+
text(str): 需要加密的字符串
|
|
74
|
+
key(str): 加密密钥
|
|
75
|
+
return:
|
|
76
|
+
str: 加密后的字符串
|
|
77
|
+
"""
|
|
78
|
+
f = Fernet(key.encode())
|
|
79
|
+
encrypted_data = f.encrypt(text.encode())
|
|
80
|
+
return encrypted_data.decode()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def decrypt_string(encrypted_text: str, key: str) -> str:
|
|
84
|
+
"""
|
|
85
|
+
description:
|
|
86
|
+
解密使用Fernet加密的字符串
|
|
87
|
+
parameters:
|
|
88
|
+
encrypted_text(str): 加密后的字符串
|
|
89
|
+
key(str): 加密密钥
|
|
90
|
+
return:
|
|
91
|
+
str: 解密后的原始字符串
|
|
92
|
+
"""
|
|
93
|
+
f = Fernet(key.encode())
|
|
94
|
+
decrypted_data = f.decrypt(encrypted_text.encode())
|
|
95
|
+
return decrypted_data.decode()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def decimal(num: float, precision=2):
|
|
99
|
+
"""
|
|
100
|
+
保留小数点后precision位
|
|
101
|
+
parameters:
|
|
102
|
+
num: float, 需要保留小数点的数字
|
|
103
|
+
precision: int, 保留小数点的位数
|
|
104
|
+
return:
|
|
105
|
+
num(float): 保留小数点后的数字
|
|
106
|
+
"""
|
|
107
|
+
num_s = f"{num:.{precision}f}"
|
|
108
|
+
return float(num_s)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def percentage(current, target):
|
|
112
|
+
"""
|
|
113
|
+
计算当前值占总值的百分比
|
|
114
|
+
parameters:
|
|
115
|
+
current: float, 当前值
|
|
116
|
+
target: float, 总值
|
|
117
|
+
return:
|
|
118
|
+
percentage_str(str): 百分比字符串
|
|
119
|
+
"""
|
|
120
|
+
percentage = decimal((current / target) * 100)
|
|
121
|
+
percentage_str = f"{percentage}%"
|
|
122
|
+
return percentage_str
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def size_unit_convert(size, input_unit="B", output_unit="MB", precision=2):
|
|
126
|
+
"""
|
|
127
|
+
单位转换
|
|
128
|
+
parameters:
|
|
129
|
+
size: float, 需要转换的文件大小
|
|
130
|
+
input_unit: str, 输入的单位,默认B
|
|
131
|
+
output_unit: str, 输出的单位,默认MB
|
|
132
|
+
precision: int, 保留小数点的位数,默认2
|
|
133
|
+
return:
|
|
134
|
+
size(float): 转换后的文件大小
|
|
135
|
+
"""
|
|
136
|
+
size_unit_list = ["B", "KB", "MB", "GB", "TB"]
|
|
137
|
+
if input_unit not in size_unit_list or output_unit not in size_unit_list:
|
|
138
|
+
return size
|
|
139
|
+
pos_input_unit = size_unit_list.index(input_unit)
|
|
140
|
+
pos_output_unit = size_unit_list.index(output_unit)
|
|
141
|
+
if pos_input_unit == pos_output_unit:
|
|
142
|
+
return size
|
|
143
|
+
|
|
144
|
+
mult_num = (
|
|
145
|
+
1 / (1024 ** (pos_output_unit - pos_input_unit))
|
|
146
|
+
if pos_input_unit < pos_output_unit
|
|
147
|
+
else 1024 ** (pos_input_unit - pos_output_unit)
|
|
148
|
+
)
|
|
149
|
+
return decimal(size * mult_num, precision)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def split_content_into_sentences(
|
|
153
|
+
content: str, remove_punctuation: bool = True
|
|
154
|
+
) -> tuple[list[str], bool]:
|
|
155
|
+
"""
|
|
156
|
+
description:
|
|
157
|
+
将内容按逗号和顿号分割成句子
|
|
158
|
+
parameters:
|
|
159
|
+
content(str): 需要分割的内容
|
|
160
|
+
return:
|
|
161
|
+
sentences(list[str]): 分割后的句子列表
|
|
162
|
+
flag(bool): 是否分割成功
|
|
163
|
+
"""
|
|
164
|
+
try:
|
|
165
|
+
split_pattern = r"[。!?;,、:]"
|
|
166
|
+
content = content.strip()
|
|
167
|
+
sentences = re.split(split_pattern, content)
|
|
168
|
+
sentences = [s.strip() for s in sentences if s.strip()]
|
|
169
|
+
|
|
170
|
+
# 对每一句话循环去除所有的空格
|
|
171
|
+
sentences = [
|
|
172
|
+
sentence.replace(" ", "")
|
|
173
|
+
for sentence in sentences
|
|
174
|
+
if sentence and sentence.strip() and sentence.strip() != ""
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
if remove_punctuation:
|
|
178
|
+
sentences = [re.sub(r"[^\w\s]", "", s) for s in sentences]
|
|
179
|
+
return sentences, True
|
|
180
|
+
except Exception as e:
|
|
181
|
+
feishu_alert.send(f"分割内容时发生错误: {traceback.format_exc()}")
|
|
182
|
+
return [], False
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def remove_all_punctuation(text: str) -> tuple[str, bool]:
|
|
186
|
+
"""
|
|
187
|
+
description:
|
|
188
|
+
去除字符串中的所有标点符号
|
|
189
|
+
parameters:
|
|
190
|
+
text(str): 需要处理的字符串
|
|
191
|
+
return:
|
|
192
|
+
text(str): 处理后的字符串
|
|
193
|
+
flag(bool): 是否处理成功
|
|
194
|
+
"""
|
|
195
|
+
try:
|
|
196
|
+
# 使用正则表达式去除所有标点符号
|
|
197
|
+
return re.sub(r"[^\w\s]", "", text), True
|
|
198
|
+
except Exception as e:
|
|
199
|
+
feishu_alert.send(f"去除标点符号时发生错误: {traceback.format_exc()}")
|
|
200
|
+
return text, False
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def file_to_base64(file_path: str) -> str:
|
|
204
|
+
"""
|
|
205
|
+
description:
|
|
206
|
+
将文件转换为base64
|
|
207
|
+
parameters:
|
|
208
|
+
file_path(str): 文件路径
|
|
209
|
+
return:
|
|
210
|
+
base64_str(str): base64字符串
|
|
211
|
+
"""
|
|
212
|
+
with open(file_path, "rb") as file:
|
|
213
|
+
return base64.b64encode(file.read()).decode("utf-8")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def execute_command(command: Union[str, List[str]]) -> str:
|
|
217
|
+
"""
|
|
218
|
+
description:
|
|
219
|
+
执行命令
|
|
220
|
+
parameters:
|
|
221
|
+
cmd(list[str]): 需要执行的命令
|
|
222
|
+
return:
|
|
223
|
+
result(str): 命令执行结果
|
|
224
|
+
"""
|
|
225
|
+
try:
|
|
226
|
+
if isinstance(command, str):
|
|
227
|
+
command = command.split()
|
|
228
|
+
print(command)
|
|
229
|
+
result = subprocess.run(
|
|
230
|
+
command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
|
231
|
+
)
|
|
232
|
+
return result.stdout.decode(), True
|
|
233
|
+
except subprocess.CalledProcessError as e:
|
|
234
|
+
feishu_alert.send(
|
|
235
|
+
f"执行命令失败,命令: {command},错误信息: {e.stderr.decode() if e.stderr else str(e)}"
|
|
236
|
+
)
|
|
237
|
+
return None, False
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
async def execute_command_async(command: Union[str, List[str]]) -> str:
|
|
241
|
+
"""
|
|
242
|
+
description:
|
|
243
|
+
异步执行命令
|
|
244
|
+
parameters:
|
|
245
|
+
command(list[str]): 需要执行的命令
|
|
246
|
+
return:
|
|
247
|
+
result(str): 命令执行结果
|
|
248
|
+
"""
|
|
249
|
+
try:
|
|
250
|
+
if isinstance(command, str):
|
|
251
|
+
command = command.split()
|
|
252
|
+
print(command)
|
|
253
|
+
result = await asyncio.create_subprocess_exec(
|
|
254
|
+
*command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
|
|
255
|
+
)
|
|
256
|
+
stdout, stderr = await result.communicate()
|
|
257
|
+
return stdout.decode(), True
|
|
258
|
+
except subprocess.CalledProcessError as e:
|
|
259
|
+
feishu_alert.send(
|
|
260
|
+
f"异步执行命令失败,命令: {command},错误信息: {e.stderr.decode() if e.stderr else str(e)}"
|
|
261
|
+
)
|
|
262
|
+
return None, False
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def get_variable_type(variable: object) -> str:
|
|
266
|
+
"""
|
|
267
|
+
description:
|
|
268
|
+
获取变量类型
|
|
269
|
+
parameters:
|
|
270
|
+
variable(object): 需要获取类型的变量
|
|
271
|
+
return:
|
|
272
|
+
variable_type(str): 变量类型
|
|
273
|
+
"""
|
|
274
|
+
return type(variable).__name__
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def extract_json_from_markdown(content: str) -> dict:
|
|
278
|
+
"""
|
|
279
|
+
description:
|
|
280
|
+
从Markdown文本中提取JSON内容
|
|
281
|
+
parameters:
|
|
282
|
+
content(str): Markdown文本
|
|
283
|
+
return:
|
|
284
|
+
json_content(dict): JSON内容
|
|
285
|
+
"""
|
|
286
|
+
# 首先尝试匹配 ```json 格式
|
|
287
|
+
json_match = re.search(r"```json\n(.*?)\n```", content, re.DOTALL)
|
|
288
|
+
if json_match:
|
|
289
|
+
return json.loads(json_match.group(1))
|
|
290
|
+
|
|
291
|
+
# 如果没有找到 ```json 格式,尝试直接匹配 JSON 对象
|
|
292
|
+
json_match = re.search(r"({[\s\S]*})", content)
|
|
293
|
+
if json_match:
|
|
294
|
+
return json.loads(json_match.group(1))
|
|
295
|
+
|
|
296
|
+
# 如果还是没有找到,尝试直接解析整个内容
|
|
297
|
+
try:
|
|
298
|
+
return json.loads(content)
|
|
299
|
+
except:
|
|
300
|
+
return {}
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def get_ssh_config():
|
|
304
|
+
"""
|
|
305
|
+
descrption:
|
|
306
|
+
获取~/.ssh/config中的配置信息
|
|
307
|
+
return:
|
|
308
|
+
configs(list): 配置信息 [{"host": "", "hostname": "", "user": "", "identityfile": ""}, ...]
|
|
309
|
+
"""
|
|
310
|
+
ssh_config_file = os.path.expanduser("~/.ssh/config")
|
|
311
|
+
configs = []
|
|
312
|
+
current_config = {}
|
|
313
|
+
|
|
314
|
+
with open(ssh_config_file, "r") as f:
|
|
315
|
+
for line in f.readlines():
|
|
316
|
+
line = line.strip()
|
|
317
|
+
if not line:
|
|
318
|
+
continue
|
|
319
|
+
|
|
320
|
+
if line.startswith("Host "):
|
|
321
|
+
if current_config:
|
|
322
|
+
configs.append(current_config)
|
|
323
|
+
current_config = {}
|
|
324
|
+
current_config["host"] = line.split()[1]
|
|
325
|
+
elif line.startswith("HostName "):
|
|
326
|
+
current_config["hostname"] = line.split()[1]
|
|
327
|
+
elif line.startswith("User "):
|
|
328
|
+
current_config["user"] = line.split()[1]
|
|
329
|
+
elif line.startswith("IdentityFile "):
|
|
330
|
+
current_config["identityfile"] = os.path.expanduser(line.split()[1])
|
|
331
|
+
|
|
332
|
+
if current_config:
|
|
333
|
+
configs.append(current_config)
|
|
334
|
+
|
|
335
|
+
return configs
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def execute_command_through_ssh_stream(
|
|
339
|
+
hostname: str, command: str
|
|
340
|
+
) -> Generator[str, None, None]:
|
|
341
|
+
"""
|
|
342
|
+
descrption:
|
|
343
|
+
SSH到线上机器并执行命令
|
|
344
|
+
parameters:
|
|
345
|
+
hostname(str): 线上机器的IP地址
|
|
346
|
+
command(str): 要执行的命令
|
|
347
|
+
return:
|
|
348
|
+
output(generator): 命令的输出生成器
|
|
349
|
+
"""
|
|
350
|
+
ssh_config = next(
|
|
351
|
+
(config for config in get_ssh_config() if config.get("hostname") == hostname),
|
|
352
|
+
None,
|
|
353
|
+
)
|
|
354
|
+
if not ssh_config:
|
|
355
|
+
raise Exception("SSH 配置获取失败")
|
|
356
|
+
|
|
357
|
+
ssh = paramiko.SSHClient()
|
|
358
|
+
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
359
|
+
ssh.connect(
|
|
360
|
+
ssh_config["hostname"],
|
|
361
|
+
username=ssh_config["user"],
|
|
362
|
+
key_filename=ssh_config["identityfile"],
|
|
363
|
+
)
|
|
364
|
+
try:
|
|
365
|
+
stdin, stdout, stderr = ssh.exec_command(command, get_pty=True)
|
|
366
|
+
stdout.channel.settimeout(None)
|
|
367
|
+
|
|
368
|
+
while line := stdout.readline():
|
|
369
|
+
yield line.strip() + "\n"
|
|
370
|
+
|
|
371
|
+
if stderr.readline():
|
|
372
|
+
raise Exception(f"在host: {hostname}上执行命令{command}失败")
|
|
373
|
+
finally:
|
|
374
|
+
ssh.close()
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def execute_command_through_ssh(hostname: str, command: str) -> str:
|
|
378
|
+
"""
|
|
379
|
+
descrption:
|
|
380
|
+
SSH到线上机器并执行命令
|
|
381
|
+
parameters:
|
|
382
|
+
hostname(str): 线上机器的IP地址
|
|
383
|
+
command(str): 要执行的命令
|
|
384
|
+
return:
|
|
385
|
+
output(str): 命令的输出
|
|
386
|
+
"""
|
|
387
|
+
result = ""
|
|
388
|
+
for line in execute_command_through_ssh_stream(hostname, command):
|
|
389
|
+
result += line
|
|
390
|
+
return result
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pixelarraylib
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: PixelArray Python开发工具库 - 包含阿里云服务、数据库工具、装饰器、监控等功能
|
|
5
|
+
Author-email: Lu qi <qi.lu@pixelarrayai.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/pixelarrayai/general_pythondevutils_lib
|
|
8
|
+
Project-URL: Bug Reports, https://gitlab.com/pixelarrayai/general_pythondevutils_lib/-/issues
|
|
9
|
+
Project-URL: Source, https://gitlab.com/pixelarrayai/general_pythondevutils_lib
|
|
10
|
+
Keywords: python,utils,aliyun,database,tools,pixelarray
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: alibabacloud_tea_util
|
|
25
|
+
Requires-Dist: alibabacloud_cms20190101
|
|
26
|
+
Requires-Dist: alibabacloud_green20220302
|
|
27
|
+
Requires-Dist: alibabacloud_dm20151123
|
|
28
|
+
Requires-Dist: alibabacloud_fc20230330
|
|
29
|
+
Requires-Dist: alibabacloud_darabonba_stream
|
|
30
|
+
Requires-Dist: alibabacloud_dysmsapi20170525
|
|
31
|
+
Requires-Dist: alibabacloud_sts20150401
|
|
32
|
+
Requires-Dist: alibabacloud_alidns20150109
|
|
33
|
+
Requires-Dist: alibabacloud_eci20180808
|
|
34
|
+
Requires-Dist: alibabacloud_bssopenapi20171214
|
|
35
|
+
Requires-Dist: oss2
|
|
36
|
+
Requires-Dist: pymysql
|
|
37
|
+
Requires-Dist: aiomysql
|
|
38
|
+
Requires-Dist: redis
|
|
39
|
+
Requires-Dist: redis[async]
|
|
40
|
+
Requires-Dist: requests
|
|
41
|
+
Requires-Dist: aiohttp
|
|
42
|
+
Requires-Dist: asyncio
|
|
43
|
+
Requires-Dist: setuptools
|
|
44
|
+
Requires-Dist: cffi
|
|
45
|
+
Requires-Dist: cryptography
|
|
46
|
+
Requires-Dist: pandas
|
|
47
|
+
Requires-Dist: paramiko
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# PixelArrayLib - PixelArray Python开发工具库
|
|
51
|
+
|
|
52
|
+
PixelArrayLib是一个功能丰富的Python开发工具库,包含阿里云服务、数据库工具、装饰器、监控等功能,同时提供便捷的命令行工具。
|
|
53
|
+
|
|
54
|
+
## 安装
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install pixelarraylib
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 使用方法
|
|
61
|
+
|
|
62
|
+
### 1. Python程序中使用
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# 导入pixelarraylib模块
|
|
66
|
+
import arraylib
|
|
67
|
+
|
|
68
|
+
# 使用各种功能模块
|
|
69
|
+
from arraylib.aliyun import some_service
|
|
70
|
+
from arraylib.db_utils import database_tools
|
|
71
|
+
from arraylib.decorators import useful_decorators
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. 命令行工具使用
|
|
75
|
+
|
|
76
|
+
安装后,你可以在命令行中直接使用 `pixelarraylib` 命令:
|
|
77
|
+
|
|
78
|
+
#### 创建测试用例文件
|
|
79
|
+
```bash
|
|
80
|
+
# 一键创建所有测试用例文件
|
|
81
|
+
pixelarraylib create_test_case_files
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### 代码提交统计
|
|
85
|
+
```bash
|
|
86
|
+
# 统计最近30天的代码提交
|
|
87
|
+
pixelarraylib summary_code_count
|
|
88
|
+
|
|
89
|
+
# 统计指定日期范围的提交
|
|
90
|
+
pixelarraylib summary_code_count --since="2025-05-09"
|
|
91
|
+
|
|
92
|
+
# 统计特定作者的提交
|
|
93
|
+
pixelarraylib summary_code_count --author="张三"
|
|
94
|
+
|
|
95
|
+
# 输出到CSV文件
|
|
96
|
+
pixelarraylib summary_code_count --output=stats.csv
|
|
97
|
+
|
|
98
|
+
# 只统计特定文件类型
|
|
99
|
+
pixelarraylib summary_code_count --file-types="py,js,vue"
|
|
100
|
+
|
|
101
|
+
# 查看帮助信息
|
|
102
|
+
pixelarraylib summary_code_count --help
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 功能特性
|
|
106
|
+
|
|
107
|
+
- **阿里云服务集成**: 包含CMS、Green、DM、FC、SMS、STS等服务
|
|
108
|
+
- **数据库工具**: MySQL、Redis等数据库操作工具
|
|
109
|
+
- **Web框架**: FastAPI集成
|
|
110
|
+
- **实用工具**: 二维码生成、加密解密、XML处理等
|
|
111
|
+
- **命令行工具**: 测试用例生成、代码统计等实用脚本
|
|
112
|
+
|
|
113
|
+
## 开发
|
|
114
|
+
|
|
115
|
+
### 本地开发安装
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# 克隆仓库
|
|
119
|
+
git clone https://gitlab.com/pixelarrayai/general_pythondevutils_lib.git
|
|
120
|
+
cd general_pythondevutils_lib
|
|
121
|
+
|
|
122
|
+
# 安装开发依赖
|
|
123
|
+
pip install -e .
|
|
124
|
+
|
|
125
|
+
# 测试命令行工具
|
|
126
|
+
pixelarraylib --help
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 添加新的命令行工具
|
|
130
|
+
|
|
131
|
+
1. 在 `arraylib/scripts/` 目录下创建新的脚本文件
|
|
132
|
+
2. 在 `arraylib/__main__.py` 中添加新的命令选项
|
|
133
|
+
3. 更新 `arraylib/scripts/__init__.py` 导出新功能
|
|
134
|
+
|
|
135
|
+
## 许可证
|
|
136
|
+
|
|
137
|
+
MIT License
|
|
138
|
+
|
|
139
|
+
## 作者
|
|
140
|
+
|
|
141
|
+
Lu qi (qi.lu@pixelarrayai.com)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
arraylib/__init__.py,sha256=SH1Y-v6CQYC8kLfivhghAUstP4tM880SeZVxh7SBZkQ,847
|
|
2
|
+
arraylib/__main__.py,sha256=FF3vdP_eCfw-jDpJFWvzLXTitv4Gn96x-yEtpwiB0vw,5000
|
|
3
|
+
arraylib/aliyun/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
arraylib/aliyun/aliyun_email.py,sha256=8lnkPryVlTLV8DOkcmi6bE100hFe-vu2Navxlpul_u8,4949
|
|
5
|
+
arraylib/aliyun/billing.py,sha256=v46OBzmqDubHLxvkHwMPjX-ZFdk2Z6ze-lfxzb0uJgE,21509
|
|
6
|
+
arraylib/aliyun/content_scanner.py,sha256=q7MXlKeDgf6jHJKyQwF4SCdMYcznL76ZVb0Kw9clwEc,9370
|
|
7
|
+
arraylib/aliyun/domain.py,sha256=pspT2f5hdT_wbyqiHmYJeXsKioO9gR7DGcVQ8oWEkEc,13815
|
|
8
|
+
arraylib/aliyun/eci.py,sha256=jJrc3sBt0R_YbwoyIt-oUOKfk4Txxa8rYzMYqa8vXEQ,1538
|
|
9
|
+
arraylib/aliyun/ecs.py,sha256=jaj_IEGJMlDHeKOtGh4jRmiCbYlbqXdUmCzJ30KxZXc,2874
|
|
10
|
+
arraylib/aliyun/fc.py,sha256=FKP80G1D_RJDua1Y12_MHaiLhrLgi92naK7dmx-kjBo,5946
|
|
11
|
+
arraylib/aliyun/oss.py,sha256=x48u5586oP6UiWNiKdTBraiTek2kfIxaV2ejzya9zLc,22257
|
|
12
|
+
arraylib/aliyun/sms.py,sha256=JrB-JS6RC29jJpv6ar3Inmd1AAg2lcFXRBjoqDzJdRQ,2225
|
|
13
|
+
arraylib/aliyun/sts.py,sha256=vjAxQs2kNU6aMgAbp6TpWz-PekB0IYxtNFSMQOlphC4,4517
|
|
14
|
+
arraylib/db_utils/mysql.py,sha256=5VUY07O3EC4CNeQJOr3eH9whxi5roSjNY_Wsn1V7tOU,17889
|
|
15
|
+
arraylib/db_utils/redis.py,sha256=LKbsa9JmyGVjA99xCx90zTLnMcm4JxXsiZhlJ610ynQ,11118
|
|
16
|
+
arraylib/decorators/__init__.py,sha256=9H_w5GkRg38zF1nGJ904Kh6AIACU3yZbBW7cporOMjo,236
|
|
17
|
+
arraylib/decorators/decorators.py,sha256=vzvwn-1YEiyYo6aS05yva5VQvCLEGnCBQcmMClZwDpc,6551
|
|
18
|
+
arraylib/gitlab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
arraylib/gitlab/code_analyzer.py,sha256=sRwe43ozGPqwfXhjl_5fQxXuf6e_63NPF5pEZNo1PmY,12431
|
|
20
|
+
arraylib/gitlab/pypi_package_manager.py,sha256=c-fRS-Nz6z9XtmjpNizDbp8ZygRRbNfWVZav_j0RHo8,2377
|
|
21
|
+
arraylib/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
arraylib/monitor/feishu.py,sha256=BKOfqRO_pPwXx6NFBboqAs1N3mPd3KsPSBVfS1FcJ2c,4851
|
|
23
|
+
arraylib/net/request.py,sha256=NT-tl-2cEFF6hO5fejbTphl3P7P7JWxsXLt-GMYjgaU,4034
|
|
24
|
+
arraylib/scripts/__init__.py,sha256=O_Y8hCOrS5Y-c0zKN9pijtLDOyMW6tLqaK884eocJZI,689
|
|
25
|
+
arraylib/scripts/collect_code_to_txt.py,sha256=sMGh5Ccp-Gu9g8SbaUWqWmd2EF3_drUcKtcbn3fLVxI,12149
|
|
26
|
+
arraylib/scripts/create_test_case_files.py,sha256=HpOM2-OePXkU7TEQfK64K7CPnOtkWjTmIYykkIzp3DA,2807
|
|
27
|
+
arraylib/scripts/nginx_proxy_to_ecs.py,sha256=Ao6-gI4YTndclX2RAje1FOmKBvCu6-cLkwWHgzdozkY,3708
|
|
28
|
+
arraylib/scripts/remove_empty_lines.py,sha256=PyVt-6ZPWWPpZ3Cmjv90UgTWZhIxRbcLVC3i5EaiqIE,3519
|
|
29
|
+
arraylib/scripts/summary_code_count.py,sha256=cWstdJveYSNQed8cvvIxS4cO-wnlfgPxNgQ5jyiCUZA,15345
|
|
30
|
+
arraylib/system/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
arraylib/system/common.py,sha256=fZSfdiZhK1aAxLxVhGPlkryiqZvG1lE7-Gca4XO3FAg,11414
|
|
32
|
+
pixelarraylib-1.0.0.dist-info/licenses/LICENSE,sha256=O-g1dUr0U50rSIvmWE9toiVkSgFpVt72_MHITbWvAqA,1067
|
|
33
|
+
pixelarraylib-1.0.0.dist-info/METADATA,sha256=sbRq3-UOmCDox85b4S1R26defSp8JM4zH-E7gf3iCJ0,4042
|
|
34
|
+
pixelarraylib-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
35
|
+
pixelarraylib-1.0.0.dist-info/entry_points.txt,sha256=GMCuPtjh_ngMrwkmltYvQL8nzpp4HXXe7HEYvp03WVc,57
|
|
36
|
+
pixelarraylib-1.0.0.dist-info/top_level.txt,sha256=DCfj9KgMHJXrggUf8kdR2JJOS1RzEIbKt4_JaccrZ58,9
|
|
37
|
+
pixelarraylib-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 PixelArray
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
arraylib
|