ezKit 1.10.3__py3-none-any.whl → 1.10.5__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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 = '/bin/bash',
1026
- sh_option: str | None = None,
1007
+ sh_shell: str = "/bin/bash",
1008
+ sh_option: Optional[str] = None,
1027
1009
  **kwargs
1028
- ) -> subprocess.CompletedProcess | None:
1029
- """run shell command or script"""
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
- match True:
1032
- case True if not check_file_type(sh_shell, 'file'):
1033
- return None
1034
- case True if isTrue(sh_shell, str) and isTrue(command, str):
1035
- if isfile is True:
1036
- if sh_option is None:
1037
- return subprocess.run([sh_shell, command], **kwargs, check=False)
1038
- return subprocess.run([sh_shell, sh_option, command], **kwargs, check=False)
1039
- if sh_option is None:
1040
- sh_option = '-c'
1041
- return subprocess.run([sh_shell, sh_option, command], **kwargs, check=False)
1042
- case _:
1043
- return None
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.10.3
3
+ Version: 1.10.5
4
4
  Summary: Easy Kit
5
5
  Author: septvean
6
6
  Author-email: septvean@gmail.com
@@ -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=Rc4RgjHOOtf5dMLvMkK1beRfbIai5E1x4HTsDwKsA-Q,6822
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=k3hSnOwNSyyRDVwfEzQUXQh_oJJ51KOT-PvLFPYOtOE,42517
12
+ ezKit/utils.py,sha256=ILLaptYUSalERbCOhmoq4w0ZNZgj9yurpHEZwjRMZ8w,42387
13
13
  ezKit/xftp.py,sha256=XyIdr_2rxRVLqPofG6fIYWhAMVsFwTyp46dg5P9FLW4,7774
14
- ezKit-1.10.3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
- ezKit-1.10.3.dist-info/METADATA,sha256=19kgwO-MdMKnsJvQ55DaYMC07qdEmyoJ29cj0qaIF9A,191
16
- ezKit-1.10.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
17
- ezKit-1.10.3.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
18
- ezKit-1.10.3.dist-info/RECORD,,
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