ezKit 1.10.4__py3-none-any.whl → 1.10.6__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,125 +92,272 @@ 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:
88
100
  outcsv = csv.writer(file)
89
101
  outcsv.writerow(data.keys())
90
102
  outcsv.writerows(data)
103
+ logger.success("save to csv success")
91
104
  return True
92
105
  except Exception as e:
106
+ logger.error("save to csv failed")
93
107
  logger.exception(e)
94
108
  return False
95
109
 
96
- def execute(
97
- self,
98
- sql: str | None = None,
99
- sql_file: str | None = None,
100
- sql_file_kwargs: dict | None = None,
101
- csv_file: str | None = None,
102
- csv_file_kwargs: dict | None = None
103
- ) -> CursorResult[Any] | bool:
104
- """"运行"""
110
+ # ----------------------------------------------------------------------------------------------
105
111
 
106
- # ------------------------------------------------------------
112
+ # def execute(
113
+ # self,
114
+ # sql: str | None = None,
115
+ # sql_file: str | None = None,
116
+ # sql_file_kwargs: dict | None = None,
117
+ # csv_file: str | None = None,
118
+ # csv_file_kwargs: dict | None = None
119
+ # ) -> CursorResult[Any] | bool:
120
+ # """"运行"""
107
121
 
108
- # 提取 SQL
109
- # 如果 sql 和 sql_file 同时存在, 优先执行 sql
122
+ # # ------------------------------------------------------------
110
123
 
111
- sql_object = None
124
+ # # 提取 SQL
125
+ # # 如果 sql 和 sql_file 同时存在, 优先执行 sql
112
126
 
113
- info: str = f"""Extract SQL: {sql}"""
127
+ # sql_object = None
114
128
 
115
- try:
129
+ # info: str = f"""Extract SQL: {sql}"""
116
130
 
117
- logger.info(f"{info} ......")
131
+ # try:
118
132
 
119
- if utils.isTrue(sql, str):
133
+ # logger.info(f"{info} ......")
120
134
 
121
- sql_object = sql
135
+ # if utils.isTrue(sql, str):
122
136
 
123
- elif sql_file is not None and utils.isTrue(sql_file, str):
137
+ # sql_object = sql
124
138
 
125
- # 判断文件是否存在
126
- if isinstance(sql_file, str) and utils.check_file_type(sql_file, "file") is False:
139
+ # elif sql_file is not None and utils.isTrue(sql_file, str):
127
140
 
128
- logger.error(f"No such file: {sql_file}")
129
- return False
141
+ # # 判断文件是否存在
142
+ # if isinstance(sql_file, str) and utils.check_file_type(sql_file, "file") is False:
130
143
 
131
- if isinstance(sql_file, str) and utils.isTrue(sql_file, str):
144
+ # logger.error(f"No such file: {sql_file}")
145
+ # return False
132
146
 
133
- # 读取文件内容
134
- if sql_file_kwargs is not None and utils.isTrue(sql_file_kwargs, dict):
135
- with open(sql_file, "r", encoding="utf-8", **sql_file_kwargs) as _file:
136
- sql_object = _file.read()
137
- else:
138
- with open(sql_file, "r", encoding="utf-8") as _file:
139
- sql_object = _file.read()
147
+ # if isinstance(sql_file, str) and utils.isTrue(sql_file, str):
140
148
 
141
- else:
149
+ # # 读取文件内容
150
+ # if sql_file_kwargs is not None and utils.isTrue(sql_file_kwargs, dict):
151
+ # with open(sql_file, "r", encoding="utf-8", **sql_file_kwargs) as _file:
152
+ # sql_object = _file.read()
153
+ # else:
154
+ # with open(sql_file, "r", encoding="utf-8") as _file:
155
+ # sql_object = _file.read()
142
156
 
143
- logger.error("SQL or SQL file error")
144
- logger.error(f"{info} [failure]")
145
- return False
157
+ # else:
146
158
 
147
- logger.success(f'{info} [success]')
159
+ # logger.error("SQL or SQL file error")
160
+ # logger.error(f"{info} [failure]")
161
+ # return False
148
162
 
149
- except Exception as e:
163
+ # logger.success(f'{info} [success]')
150
164
 
151
- logger.error(f"{info} [failure]")
152
- logger.exception(e)
153
- return False
165
+ # except Exception as e:
166
+
167
+ # logger.error(f"{info} [failure]")
168
+ # logger.exception(e)
169
+ # return False
170
+
171
+ # # ------------------------------------------------------------
172
+
173
+ # # 执行 SQL
174
+
175
+ # info = f"""Execute SQL: {sql_object}"""
176
+
177
+ # try:
178
+
179
+ # logger.info(f"{info} ......")
180
+
181
+ # with self.engine.connect() as connect:
182
+
183
+ # # 执行SQL
184
+ # if sql_object is None:
185
+ # return False
186
+
187
+ # result = connect.execute(text(sql_object))
188
+
189
+ # connect.commit()
190
+
191
+ # if csv_file is None:
192
+ # # 如果 csv_file 没有定义, 则直接返回结果
193
+ # logger.success(f'{info} [success]')
194
+ # return result
195
+
196
+ # # 如果 csv_file 有定义, 则保存结果到 csv_file
197
+ # info_of_save = f"Save result to file: {csv_file}"
198
+ # logger.info(f"{info_of_save} .......")
199
+
200
+ # # 保存结果
201
+ # if isinstance(csv_file_kwargs, dict) and utils.isTrue(csv_file_kwargs, dict):
202
+ # with open(csv_file, "w", encoding="utf-8", **csv_file_kwargs) as _file:
203
+ # result_of_save = self._result_save(_file, result)
204
+ # else:
205
+ # with open(csv_file, "w", encoding="utf-8") as _file:
206
+ # result_of_save = self._result_save(_file, result)
207
+
208
+ # # 检查保存结果
209
+ # if result_of_save is True:
210
+ # logger.success(f'{info_of_save} [success]')
211
+ # logger.success(f'{info} [success]')
212
+ # return True
213
+
214
+ # logger.error(f"{info_of_save} [failure]")
215
+ # logger.error(f"{info} [failure]")
216
+ # return False
217
+
218
+ # except Exception as e:
219
+
220
+ # logger.error(f'{info} [failure]')
221
+ # logger.exception(e)
222
+ # return False
154
223
 
155
- # ------------------------------------------------------------
224
+ # ----------------------------------------------------------------------------------------------
156
225
 
157
- # 执行 SQL
226
+ def connect_execute(
227
+ self,
228
+ sql: str | None = None,
229
+ read_sql_file: dict | None = None,
230
+ save_to_csv: dict | None = None
231
+ ) -> CursorResult[Any] | bool | None:
232
+
233
+ info: str = 'Database connect execute'
234
+
235
+ logger.info(f"{info} ......")
158
236
 
159
- info = f"""Execute SQL: {sql_object}"""
237
+ sql_statement: str = ""
238
+
239
+ # ------------------------------------------------------------------------------------------
160
240
 
161
241
  try:
242
+ # SQL文件优先
243
+ if isinstance(read_sql_file, dict) and utils.isTrue(read_sql_file, dict):
244
+ read_sql_file.pop("encoding")
245
+ read_sql_file_kwargs: dict = {
246
+ "mode": "r",
247
+ "encoding": "utf-8",
248
+ **read_sql_file
249
+ }
250
+ with open(encoding="utf-8", **read_sql_file_kwargs) as _file:
251
+ sql_statement = _file.read()
252
+ else:
253
+ if not (isinstance(sql, str) and utils.check_arguments([(sql, str, "sql")])):
254
+ return None
255
+ sql_statement = sql
256
+ except Exception as e:
257
+ logger.exception(e)
258
+ return None
162
259
 
163
- logger.info(f"{info} ......")
260
+ # ------------------------------------------------------------------------------------------
261
+
262
+ if not self.connect_test():
263
+ return None
264
+
265
+ # ------------------------------------------------------------------------------------------
266
+
267
+ # 创建一个连接
268
+ with self.engine.connect() as connection:
164
269
 
165
- with self.engine.connect() as connect:
270
+ # 开始一个事务
271
+ with connection.begin(): # 事务会自动提交或回滚
166
272
 
167
- # 执行SQL
168
- if sql_object is None:
169
- return False
273
+ try:
170
274
 
171
- result = connect.execute(text(sql_object))
275
+ # 执行 SQL 查询
276
+ result = connection.execute(text(sql_statement))
172
277
 
173
- connect.commit()
278
+ # 执行成功
279
+ logger.success(f"{info} [success]")
280
+
281
+ # 返回查询结果
282
+ if isinstance(save_to_csv, dict) and utils.isTrue(save_to_csv, dict):
283
+ save_to_csv_kwargs: dict = {
284
+ "mode": "w",
285
+ "encoding": "utf-8",
286
+ **save_to_csv
287
+ }
288
+ with open(encoding="utf-8", **save_to_csv_kwargs) as _file:
289
+ return self._result_save(_file, result)
174
290
 
175
- if csv_file is None:
176
- # 如果 csv_file 没有定义, 则直接返回结果
177
- logger.success(f'{info} [success]')
178
291
  return result
179
292
 
180
- # 如果 csv_file 有定义, 则保存结果到 csv_file
181
- info_of_save = f"Save result to file: {csv_file}"
182
- logger.info(f"{info_of_save} .......")
293
+ except Exception as e:
294
+ # 发生异常时回滚事务
295
+ logger.info(f"{info} [failed]")
296
+ logger.exception(e)
297
+ return None
183
298
 
184
- # 保存结果
185
- if isinstance(csv_file_kwargs, dict) and utils.isTrue(csv_file_kwargs, dict):
186
- with open(csv_file, "w", encoding="utf-8", **csv_file_kwargs) as _file:
187
- result_of_save = self._result_save(_file, result)
188
- else:
189
- with open(csv_file, "w", encoding="utf-8") as _file:
190
- result_of_save = self._result_save(_file, result)
299
+ # ----------------------------------------------------------------------------------------------
191
300
 
192
- # 检查保存结果
193
- if result_of_save is True:
194
- logger.success(f'{info_of_save} [success]')
195
- logger.success(f'{info} [success]')
196
- return True
301
+ def read_with_pandas(
302
+ self,
303
+ method: str = "read_sql",
304
+ result_type: str = "df",
305
+ **kwargs
306
+ ) -> pd.DataFrame | list | dict:
307
+ """读取数据"""
197
308
 
198
- logger.error(f"{info_of_save} [failure]")
199
- logger.error(f"{info} [failure]")
200
- return False
309
+ # 使用SQL查询数据: 使用 pd.read_sql 的参数
310
+ # read_data_with_pandas(by="sql", result_type="df", sql="SELECT * FROM table ORDER BY date DESC LIMIT 1")
201
311
 
202
- except Exception as e:
312
+ # 读取表中的数据: 使用 pd.read_sql_table 的参数
313
+ # read_data_with_pandas(by="table", result_type="df", table_name="ashare")
203
314
 
204
- logger.error(f'{info} [failure]')
315
+ data: pd.DataFrame = pd.DataFrame()
316
+
317
+ if not utils.check_arguments([(method, str, "method")]):
318
+ return data
319
+
320
+ if not utils.check_arguments([(result_type, str, "result_type")]):
321
+ return data
322
+
323
+ info: str = "read data"
324
+
325
+ try:
326
+
327
+ logger.info(f"{info} ......")
328
+
329
+ # 从 kwargs 中删除 con 键
330
+ kwargs.pop('con', None)
331
+
332
+ match method:
333
+ case "read_sql":
334
+ data = pd.read_sql(con=self.engine, **kwargs)
335
+ case "read_sql_query":
336
+ data = pd.read_sql_query(con=self.engine, **kwargs)
337
+ case "read_sql_table":
338
+ data = pd.read_sql_table(con=self.engine, **kwargs)
339
+ case _:
340
+ logger.error(f"{info} [incorrect method: {method}]")
341
+ return data
342
+
343
+ if data.empty:
344
+ logger.error(f"{info} [failed]")
345
+ return data
346
+
347
+ logger.success(f"{info} [success]")
348
+
349
+ match result_type:
350
+ case "json":
351
+ return json.loads(data.to_json(orient='records'))
352
+ case "dict":
353
+ return data.to_dict()
354
+ case "list":
355
+ # https://stackoverflow.com/a/26716774
356
+ return data.to_dict('list')
357
+ case _:
358
+ return data
359
+
360
+ except Exception as e:
361
+ logger.error(f"{info} [failed]")
205
362
  logger.exception(e)
206
- return False
363
+ return data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.10.4
3
+ Version: 1.10.6
4
4
  Summary: Easy Kit
5
5
  Author: septvean
6
6
  Author-email: septvean@gmail.com
@@ -2,7 +2,7 @@ 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=Hc1XWWnBwrnnaV8vOH9DAvZXz1DaEVEXSwKfWakX89I,12584
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
@@ -11,8 +11,8 @@ ezKit/sendemail.py,sha256=tRXCsJm_RfTJ9xEWe_lTQ5kOs2JxHGPXvq0oWA7prq0,7263
11
11
  ezKit/token.py,sha256=HKREyZj_T2S8-aFoFIrBXTaCKExQq4zE66OHXhGHqQg,1750
12
12
  ezKit/utils.py,sha256=ILLaptYUSalERbCOhmoq4w0ZNZgj9yurpHEZwjRMZ8w,42387
13
13
  ezKit/xftp.py,sha256=XyIdr_2rxRVLqPofG6fIYWhAMVsFwTyp46dg5P9FLW4,7774
14
- ezKit-1.10.4.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
- ezKit-1.10.4.dist-info/METADATA,sha256=uH8X29vT0V5J3nwzW7pwMvgor45UyDqw_1iGCwU_9A4,191
16
- ezKit-1.10.4.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
17
- ezKit-1.10.4.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
18
- ezKit-1.10.4.dist-info/RECORD,,
14
+ ezKit-1.10.6.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
+ ezKit-1.10.6.dist-info/METADATA,sha256=M7MZnhU7VDU0Zx7TG8Lrn_t_IS0E46zcyzVUS3EDRuc,191
16
+ ezKit-1.10.6.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
17
+ ezKit-1.10.6.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
18
+ ezKit-1.10.6.dist-info/RECORD,,
File without changes