ezKit 1.10.3__py3-none-any.whl → 1.10.5__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.
- ezKit/database.py +57 -0
- ezKit/utils.py +35 -36
- {ezKit-1.10.3.dist-info → ezKit-1.10.5.dist-info}/METADATA +1 -1
- {ezKit-1.10.3.dist-info → ezKit-1.10.5.dist-info}/RECORD +7 -7
- {ezKit-1.10.3.dist-info → ezKit-1.10.5.dist-info}/LICENSE +0 -0
- {ezKit-1.10.3.dist-info → ezKit-1.10.5.dist-info}/WHEEL +0 -0
- {ezKit-1.10.3.dist-info → ezKit-1.10.5.dist-info}/top_level.txt +0 -0
ezKit/database.py
CHANGED
@@ -6,8 +6,10 @@
|
|
6
6
|
# PostgreSQL 14 Data Types
|
7
7
|
# https://www.postgresql.org/docs/14/datatype.html
|
8
8
|
import csv
|
9
|
+
import json
|
9
10
|
from typing import Any
|
10
11
|
|
12
|
+
import pandas as pd
|
11
13
|
from loguru import logger
|
12
14
|
from sqlalchemy import CursorResult, Index, create_engine, text
|
13
15
|
from sqlalchemy.orm import DeclarativeBase
|
@@ -30,10 +32,14 @@ class Database():
|
|
30
32
|
else:
|
31
33
|
pass
|
32
34
|
|
35
|
+
# ----------------------------------------------------------------------------------------------
|
36
|
+
|
33
37
|
def initializer(self):
|
34
38
|
"""ensure the parent proc's database connections are not touched in the new connection pool"""
|
35
39
|
self.engine.dispose(close=False)
|
36
40
|
|
41
|
+
# ----------------------------------------------------------------------------------------------
|
42
|
+
|
37
43
|
def connect_test(self) -> bool:
|
38
44
|
info = "Database connect test"
|
39
45
|
try:
|
@@ -46,6 +52,8 @@ class Database():
|
|
46
52
|
logger.exception(e)
|
47
53
|
return False
|
48
54
|
|
55
|
+
# ----------------------------------------------------------------------------------------------
|
56
|
+
|
49
57
|
def metadata_init(self, base: DeclarativeBase, **kwargs) -> bool:
|
50
58
|
# https://stackoverflow.com/questions/19175311/how-to-create-only-one-table-with-sqlalchemy
|
51
59
|
info = "Database init table"
|
@@ -60,6 +68,8 @@ class Database():
|
|
60
68
|
logger.exception(e)
|
61
69
|
return False
|
62
70
|
|
71
|
+
# ----------------------------------------------------------------------------------------------
|
72
|
+
|
63
73
|
def create_index(self, index_name, table_field) -> bool:
|
64
74
|
# 创建索引
|
65
75
|
# https://stackoverflow.com/a/41254430
|
@@ -82,6 +92,8 @@ class Database():
|
|
82
92
|
logger.error(e)
|
83
93
|
return False
|
84
94
|
|
95
|
+
# ----------------------------------------------------------------------------------------------
|
96
|
+
|
85
97
|
# 私有函数, 保存 execute 的结果到 CSV 文件
|
86
98
|
def _result_save(self, file, data) -> bool:
|
87
99
|
try:
|
@@ -93,6 +105,8 @@ class Database():
|
|
93
105
|
logger.exception(e)
|
94
106
|
return False
|
95
107
|
|
108
|
+
# ----------------------------------------------------------------------------------------------
|
109
|
+
|
96
110
|
def execute(
|
97
111
|
self,
|
98
112
|
sql: str | None = None,
|
@@ -204,3 +218,46 @@ class Database():
|
|
204
218
|
logger.error(f'{info} [failure]')
|
205
219
|
logger.exception(e)
|
206
220
|
return False
|
221
|
+
|
222
|
+
# ----------------------------------------------------------------------------------------------
|
223
|
+
|
224
|
+
def read_data_with_pandas(self, result_type: str = "df", **kwargs) -> pd.DataFrame | dict | list | None:
|
225
|
+
"""读取表中所有数据"""
|
226
|
+
|
227
|
+
# 使用 pd.read_sql_table 的参数
|
228
|
+
# read_data_with_pandas(result_type="df", table_name="ashare")
|
229
|
+
|
230
|
+
info = f"读取 {kwargs.get('table_name', None)} 表中所有数据"
|
231
|
+
|
232
|
+
try:
|
233
|
+
|
234
|
+
logger.info(f"{info} ......")
|
235
|
+
|
236
|
+
# 从 kwargs 中删除 con 键
|
237
|
+
kwargs.pop('con', None)
|
238
|
+
|
239
|
+
# 读取数据
|
240
|
+
data: pd.DataFrame = pd.read_sql_table(con=self.engine, **kwargs)
|
241
|
+
|
242
|
+
if data.empty:
|
243
|
+
logger.error(f"{info} [失败]")
|
244
|
+
return None
|
245
|
+
|
246
|
+
logger.success(f"{info} [成功]")
|
247
|
+
|
248
|
+
if utils.isTrue(result_type, str) and result_type == "json":
|
249
|
+
return json.loads(data.to_json(orient='records'))
|
250
|
+
|
251
|
+
if utils.isTrue(result_type, str) and result_type == "dict":
|
252
|
+
return data.to_dict()
|
253
|
+
|
254
|
+
if utils.isTrue(result_type, str) and result_type == "list":
|
255
|
+
# https://stackoverflow.com/a/26716774
|
256
|
+
return data.to_dict('list')
|
257
|
+
|
258
|
+
return data
|
259
|
+
|
260
|
+
except Exception as e:
|
261
|
+
logger.error(f"{info} [失败]")
|
262
|
+
logger.exception(e)
|
263
|
+
return None
|
ezKit/utils.py
CHANGED
@@ -13,7 +13,7 @@ from multiprocessing import Pool
|
|
13
13
|
from multiprocessing.pool import ThreadPool
|
14
14
|
from pathlib import Path
|
15
15
|
from shutil import rmtree
|
16
|
-
from typing import Any, Callable, List, Union
|
16
|
+
from typing import Any, Callable, List, Optional, Union
|
17
17
|
from urllib.parse import ParseResult, urlparse
|
18
18
|
from uuid import uuid4
|
19
19
|
|
@@ -1001,46 +1001,45 @@ def datetime_object(
|
|
1001
1001
|
# --------------------------------------------------------------------------------------------------
|
1002
1002
|
|
1003
1003
|
|
1004
|
-
# run_cmd = bash('echo ok', universal_newlines=True, stdout=PIPE)
|
1005
|
-
#
|
1006
|
-
# if run_cmd != None:
|
1007
|
-
# returncode = run_cmd.returncode
|
1008
|
-
# outputs = run_cmd.stdout.splitlines()
|
1009
|
-
# print(returncode, type(returncode))
|
1010
|
-
# print(outputs, type(outputs))
|
1011
|
-
#
|
1012
|
-
# # echo 'echo ok' > /tmp/ok.sh
|
1013
|
-
# run_script = bash('/tmp/ok.sh', file=True, universal_newlines=True, stdout=PIPE)
|
1014
|
-
#
|
1015
|
-
# if run_script != None:
|
1016
|
-
# returncode = run_script.returncode
|
1017
|
-
# outputs = run_script.stdout.splitlines()
|
1018
|
-
# print(returncode, type(returncode))
|
1019
|
-
# print(outputs, type(outputs))
|
1020
|
-
|
1021
|
-
|
1022
1004
|
def shell(
|
1023
1005
|
command: str,
|
1024
1006
|
isfile: bool = False,
|
1025
|
-
sh_shell: str =
|
1026
|
-
sh_option: str
|
1007
|
+
sh_shell: str = "/bin/bash",
|
1008
|
+
sh_option: Optional[str] = None,
|
1027
1009
|
**kwargs
|
1028
|
-
) -> subprocess.CompletedProcess
|
1029
|
-
"""
|
1010
|
+
) -> Optional[subprocess.CompletedProcess]:
|
1011
|
+
"""执行 Shell 命令 或 脚本"""
|
1012
|
+
|
1013
|
+
# :param command: 需要执行的命令
|
1014
|
+
# :param isfile: 是否将命令视为文件路径
|
1015
|
+
# :param sh_shell: 使用的 Shell 程序路径
|
1016
|
+
# :param sh_option: Shell 执行选项,例如 '-c'
|
1017
|
+
# :param kwargs: 其他传递给 subprocess.run 的参数
|
1018
|
+
# :return: 返回 subprocess.CompletedProcess 对象,失败时返回 None
|
1019
|
+
|
1030
1020
|
try:
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1021
|
+
|
1022
|
+
# 校验 Shell 程序路径
|
1023
|
+
if not check_file_type(sh_shell, "file"):
|
1024
|
+
logger.error(f"Invalid shell path: {sh_shell}")
|
1025
|
+
return None
|
1026
|
+
|
1027
|
+
# 校验 command 和 sh_shell 的类型
|
1028
|
+
if not (isTrue(sh_shell, str) and isTrue(command, str)):
|
1029
|
+
logger.error("Invalid shell or command input.")
|
1030
|
+
return None
|
1031
|
+
|
1032
|
+
# 构造命令
|
1033
|
+
if isfile:
|
1034
|
+
args = [sh_shell, command] if sh_option is None else [sh_shell, sh_option, command]
|
1035
|
+
else:
|
1036
|
+
sh_option = sh_option or "-c"
|
1037
|
+
args = [sh_shell, sh_option, command]
|
1038
|
+
|
1039
|
+
logger.info(f"Executing command: {args}")
|
1040
|
+
|
1041
|
+
return subprocess.run(args, **kwargs, check=False)
|
1042
|
+
|
1044
1043
|
except Exception as e:
|
1045
1044
|
logger.exception(e)
|
1046
1045
|
return None
|
@@ -2,17 +2,17 @@ ezKit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
ezKit/bottle.py,sha256=usKK1wVaZw4_D-4VwMYmOIc8jtz4TrpM30nck59HMFw,180178
|
3
3
|
ezKit/bottle_extensions.py,sha256=3reEQVZuHklXTl6r7F8kiBFFPb0RaAGc3mYJJnrMDjQ,1129
|
4
4
|
ezKit/cipher.py,sha256=0T_StbjiNI4zgrjVgcfU-ffKgu1waBA9UDudAnqFcNM,2896
|
5
|
-
ezKit/database.py,sha256=
|
5
|
+
ezKit/database.py,sha256=b_4gR_bvyC3IhP6TbmeKdVrif1DNG_NqO3YIyy-XqQE,8891
|
6
6
|
ezKit/http.py,sha256=i3Kn5AMAMicDMcDjxKKZU7zqEKTU88Ec9_LwCuBJy-0,1801
|
7
7
|
ezKit/mongo.py,sha256=dOm_1wXEPp_e8Ml5Qq78M7FDNrQUAZaThzVIiiLJJwk,2393
|
8
8
|
ezKit/qywx.py,sha256=X_H4fzP-iEqeDEbumr7D1bXi6dxczaxfO8iyutzy02s,7171
|
9
9
|
ezKit/redis.py,sha256=g2_V4jvq0djRc20jLZkgeAeF_bYrq-Rbl_kHcCUPZcA,1965
|
10
10
|
ezKit/sendemail.py,sha256=tRXCsJm_RfTJ9xEWe_lTQ5kOs2JxHGPXvq0oWA7prq0,7263
|
11
11
|
ezKit/token.py,sha256=HKREyZj_T2S8-aFoFIrBXTaCKExQq4zE66OHXhGHqQg,1750
|
12
|
-
ezKit/utils.py,sha256=
|
12
|
+
ezKit/utils.py,sha256=ILLaptYUSalERbCOhmoq4w0ZNZgj9yurpHEZwjRMZ8w,42387
|
13
13
|
ezKit/xftp.py,sha256=XyIdr_2rxRVLqPofG6fIYWhAMVsFwTyp46dg5P9FLW4,7774
|
14
|
-
ezKit-1.10.
|
15
|
-
ezKit-1.10.
|
16
|
-
ezKit-1.10.
|
17
|
-
ezKit-1.10.
|
18
|
-
ezKit-1.10.
|
14
|
+
ezKit-1.10.5.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
15
|
+
ezKit-1.10.5.dist-info/METADATA,sha256=onqUqJ4_5WVpBoLpSOis-Z6uYbmM3GCMPPrAfTvi_yw,191
|
16
|
+
ezKit-1.10.5.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
17
|
+
ezKit-1.10.5.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
|
18
|
+
ezKit-1.10.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|