ezKit 1.7.8__tar.gz → 1.8.0__tar.gz
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-1.7.8/ezKit.egg-info → ezkit-1.8.0}/PKG-INFO +1 -1
- ezkit-1.8.0/README.md +1 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/bottle.py +7 -2
- ezkit-1.8.0/ezKit/bottle_extensions.py +32 -0
- ezkit-1.8.0/ezKit/database.py +204 -0
- ezkit-1.8.0/ezKit/http.py +70 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/mongo.py +3 -3
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/redis.py +5 -4
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/sendemail.py +0 -7
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/utils.py +2 -2
- {ezkit-1.7.8 → ezkit-1.8.0/ezKit.egg-info}/PKG-INFO +1 -1
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit.egg-info/SOURCES.txt +0 -5
- {ezkit-1.7.8 → ezkit-1.8.0}/setup.py +1 -1
- ezkit-1.7.8/README.md +0 -60
- ezkit-1.7.8/ezKit/bottle_extensions.py +0 -36
- ezkit-1.7.8/ezKit/database.py +0 -171
- ezkit-1.7.8/ezKit/files.py +0 -348
- ezkit-1.7.8/ezKit/http.py +0 -71
- ezkit-1.7.8/ezKit/plots.py +0 -155
- ezkit-1.7.8/ezKit/qywx.py +0 -172
- ezkit-1.7.8/ezKit/reports.py +0 -274
- ezkit-1.7.8/ezKit/zabbix.py +0 -737
- {ezkit-1.7.8 → ezkit-1.8.0}/LICENSE +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/MANIFEST.in +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/__init__.py +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/cipher.py +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/token.py +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit/xftp.py +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit.egg-info/dependency_links.txt +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit.egg-info/requires.txt +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/ezKit.egg-info/top_level.txt +0 -0
- {ezkit-1.7.8 → ezkit-1.8.0}/setup.cfg +0 -0
ezkit-1.8.0/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Python Easy Kit
|
@@ -17,7 +17,7 @@ from __future__ import print_function
|
|
17
17
|
import sys
|
18
18
|
|
19
19
|
__author__ = 'Marcel Hellkamp'
|
20
|
-
__version__ = '0.13.
|
20
|
+
__version__ = '0.13.2'
|
21
21
|
__license__ = 'MIT'
|
22
22
|
|
23
23
|
###############################################################################
|
@@ -185,6 +185,7 @@ def depr(major, minor, cause, fix, stacklevel=3):
|
|
185
185
|
if DEBUG == 'strict':
|
186
186
|
raise DeprecationWarning(text)
|
187
187
|
warnings.warn(text, DeprecationWarning, stacklevel=stacklevel)
|
188
|
+
return DeprecationWarning(text)
|
188
189
|
|
189
190
|
|
190
191
|
def makelist(data): # This is just too handy
|
@@ -4671,5 +4672,9 @@ def _main(argv): # pragma: no coverage
|
|
4671
4672
|
config=config)
|
4672
4673
|
|
4673
4674
|
|
4674
|
-
|
4675
|
+
def main():
|
4675
4676
|
_main(sys.argv)
|
4677
|
+
|
4678
|
+
|
4679
|
+
if __name__ == '__main__': # pragma: no coverage
|
4680
|
+
main()
|
@@ -0,0 +1,32 @@
|
|
1
|
+
"""Bottle Extensions"""
|
2
|
+
from typing import Callable
|
3
|
+
|
4
|
+
from . import bottle, utils
|
5
|
+
|
6
|
+
|
7
|
+
def enable_cors(fn: Callable) -> Callable:
|
8
|
+
"""Bottle CORS"""
|
9
|
+
# 参考文档:
|
10
|
+
# - https://stackoverflow.com/a/17262900
|
11
|
+
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
12
|
+
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
13
|
+
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
14
|
+
def cors(*args, **kwargs):
|
15
|
+
bottle.response.headers['Access-Control-Allow-Headers'] = '*'
|
16
|
+
bottle.response.headers['Access-Control-Allow-Methods'] = '*'
|
17
|
+
bottle.response.headers['Access-Control-Allow-Origin'] = '*'
|
18
|
+
if bottle.request.method != 'OPTIONS':
|
19
|
+
return fn(*args, **kwargs)
|
20
|
+
return None
|
21
|
+
return cors
|
22
|
+
|
23
|
+
def request_json() -> bottle.DictProperty | None:
|
24
|
+
"""Bottle Request JSON"""
|
25
|
+
try:
|
26
|
+
data = bottle.request.json
|
27
|
+
if utils.v_true(data, dict):
|
28
|
+
return data
|
29
|
+
return None
|
30
|
+
except Exception as e:
|
31
|
+
print(e)
|
32
|
+
return None
|
@@ -0,0 +1,204 @@
|
|
1
|
+
"""
|
2
|
+
Column, Table, MetaData API
|
3
|
+
https://docs.sqlalchemy.org/en/14/core/metadata.html#column-table-metadata-api
|
4
|
+
CursorResult
|
5
|
+
https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.CursorResult
|
6
|
+
PostgreSQL 14 Data Types
|
7
|
+
https://www.postgresql.org/docs/14/datatype.html
|
8
|
+
"""
|
9
|
+
import csv
|
10
|
+
from typing import Any
|
11
|
+
|
12
|
+
from loguru import logger
|
13
|
+
from sqlalchemy import CursorResult, Index, create_engine, text
|
14
|
+
|
15
|
+
from . import utils
|
16
|
+
|
17
|
+
|
18
|
+
class Database():
|
19
|
+
"""Database"""
|
20
|
+
|
21
|
+
engine = create_engine('sqlite://')
|
22
|
+
|
23
|
+
def __init__(self, engine_url, **engine_options):
|
24
|
+
"""Initiation"""
|
25
|
+
if engine_url is not None and utils.v_true(engine_url, str):
|
26
|
+
if utils.v_true(engine_options, dict):
|
27
|
+
self.engine = create_engine(engine_url, **engine_options)
|
28
|
+
else:
|
29
|
+
self.engine = create_engine(engine_url)
|
30
|
+
else:
|
31
|
+
pass
|
32
|
+
|
33
|
+
def initializer(self):
|
34
|
+
"""ensure the parent proc's database connections are not touched in the new connection pool"""
|
35
|
+
self.engine.dispose(close=False)
|
36
|
+
|
37
|
+
def connect_test(self) -> bool:
|
38
|
+
info = "Database connect test"
|
39
|
+
try:
|
40
|
+
logger.info(f"{info} ......")
|
41
|
+
self.engine.connect()
|
42
|
+
logger.success(f"{info} [success]")
|
43
|
+
return True
|
44
|
+
except Exception as e:
|
45
|
+
logger.error(f"{info} [failure]")
|
46
|
+
logger.exception(e)
|
47
|
+
return False
|
48
|
+
|
49
|
+
def metadata_init(self, base, **kwargs) -> bool:
|
50
|
+
# https://stackoverflow.com/questions/19175311/how-to-create-only-one-table-with-sqlalchemy
|
51
|
+
info = "Database init table"
|
52
|
+
try:
|
53
|
+
logger.info(f"{info} ......")
|
54
|
+
base.metadata.drop_all(self.engine, **kwargs)
|
55
|
+
base.metadata.create_all(self.engine, **kwargs)
|
56
|
+
logger.success(f"{info} [success]")
|
57
|
+
return True
|
58
|
+
except Exception as e:
|
59
|
+
logger.error(f"{info} [failure]")
|
60
|
+
logger.exception(e)
|
61
|
+
return False
|
62
|
+
|
63
|
+
def create_index(self, index_name, table_field) -> bool:
|
64
|
+
# 创建索引
|
65
|
+
# https://stackoverflow.com/a/41254430
|
66
|
+
# 示例:
|
67
|
+
# index_name: a_share_list_code_idx1
|
68
|
+
# table_field: Table_a_share_list.code
|
69
|
+
info = "Database create index"
|
70
|
+
try:
|
71
|
+
logger.info(f"{info} ......")
|
72
|
+
idx = Index(index_name, table_field)
|
73
|
+
try:
|
74
|
+
idx.drop(bind=self.engine)
|
75
|
+
except Exception as e:
|
76
|
+
logger.exception(e)
|
77
|
+
idx.create(bind=self.engine)
|
78
|
+
logger.success(f'{info} [success]')
|
79
|
+
return True
|
80
|
+
except Exception as e:
|
81
|
+
logger.error(f'{info} [failure]')
|
82
|
+
logger.error(e)
|
83
|
+
return False
|
84
|
+
|
85
|
+
# 私有函数, 保存 execute 的结果到 CSV 文件
|
86
|
+
def _result_save(self, file, data) -> bool:
|
87
|
+
try:
|
88
|
+
outcsv = csv.writer(file)
|
89
|
+
outcsv.writerow(data.keys())
|
90
|
+
outcsv.writerows(data)
|
91
|
+
return True
|
92
|
+
except Exception as e:
|
93
|
+
logger.exception(e)
|
94
|
+
return False
|
95
|
+
|
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
|
+
"""
|
105
|
+
echo 是否打印日志
|
106
|
+
某些情况下只需要结果, 不需要日志, 将 echo 设置为 False 即可
|
107
|
+
"""
|
108
|
+
|
109
|
+
# info_prefix = '[Execute SQL]'
|
110
|
+
|
111
|
+
# ------------------------------------------------------------
|
112
|
+
|
113
|
+
# 提取 SQL
|
114
|
+
# 如果 sql 和 sql_file 同时存在, 优先执行 sql
|
115
|
+
sql_object = None
|
116
|
+
info: str = "Extract SQL"
|
117
|
+
try:
|
118
|
+
|
119
|
+
logger.info(f"{info} ......")
|
120
|
+
|
121
|
+
if utils.v_true(sql, str):
|
122
|
+
|
123
|
+
sql_object = sql
|
124
|
+
|
125
|
+
elif sql_file is not None and utils.v_true(sql_file, str):
|
126
|
+
|
127
|
+
# 判断文件是否存在
|
128
|
+
if isinstance(sql_file, str) and utils.check_file_type(sql_file, "file") is False:
|
129
|
+
|
130
|
+
logger.error(f"No such file: {sql_file}")
|
131
|
+
return False
|
132
|
+
|
133
|
+
if isinstance(sql_file, str) and utils.v_true(sql_file, str):
|
134
|
+
|
135
|
+
# 读取文件内容
|
136
|
+
if sql_file_kwargs is not None and utils.v_true(sql_file_kwargs, dict):
|
137
|
+
with open(sql_file, "r", encoding="utf-8", **sql_file_kwargs) as _file:
|
138
|
+
sql_object = _file.read()
|
139
|
+
else:
|
140
|
+
with open(sql_file, "r", encoding="utf-8") as _file:
|
141
|
+
sql_object = _file.read()
|
142
|
+
|
143
|
+
else:
|
144
|
+
|
145
|
+
logger.error("SQL or SQL file error")
|
146
|
+
logger.error(f"{info} [failure]")
|
147
|
+
return False
|
148
|
+
|
149
|
+
logger.success(f'{info} [success]')
|
150
|
+
|
151
|
+
except Exception as e:
|
152
|
+
|
153
|
+
logger.error(f"{info} [failure]")
|
154
|
+
logger.exception(e)
|
155
|
+
return False
|
156
|
+
|
157
|
+
# ------------------------------------------------------------
|
158
|
+
|
159
|
+
# 执行 SQL
|
160
|
+
info: str = "Execute SQL"
|
161
|
+
try:
|
162
|
+
|
163
|
+
logger.info(f"{info} ......")
|
164
|
+
|
165
|
+
with self.engine.connect() as connect:
|
166
|
+
|
167
|
+
# 执行SQL
|
168
|
+
if sql_object is None:
|
169
|
+
return False
|
170
|
+
|
171
|
+
result = connect.execute(text(sql_object))
|
172
|
+
|
173
|
+
if csv_file is None:
|
174
|
+
# 如果 csv_file 没有定义, 则直接返回结果
|
175
|
+
logger.success(f'{info} [success]')
|
176
|
+
return result
|
177
|
+
|
178
|
+
# 如果 csv_file 有定义, 则保存结果到 csv_file
|
179
|
+
info_of_save = f"Save result to file: {csv_file}"
|
180
|
+
logger.info(f"{info_of_save} .......")
|
181
|
+
|
182
|
+
# 保存结果
|
183
|
+
if isinstance(csv_file_kwargs, dict) and utils.v_true(csv_file_kwargs, dict):
|
184
|
+
with open(csv_file, "w", encoding="utf-8", **csv_file_kwargs) as _file:
|
185
|
+
result_of_save = self._result_save(_file, result)
|
186
|
+
else:
|
187
|
+
with open(csv_file, "w", encoding="utf-8") as _file:
|
188
|
+
result_of_save = self._result_save(_file, result)
|
189
|
+
|
190
|
+
# 检查保存结果
|
191
|
+
if result_of_save is True:
|
192
|
+
logger.success(f'{info_of_save} [success]')
|
193
|
+
logger.success(f'{info} [success]')
|
194
|
+
return True
|
195
|
+
|
196
|
+
logger.error(f"{info_of_save} [failure]")
|
197
|
+
logger.error(f"{info} [failure]")
|
198
|
+
return False
|
199
|
+
|
200
|
+
except Exception as e:
|
201
|
+
|
202
|
+
logger.error(f'{info} [failure]')
|
203
|
+
logger.exception(e)
|
204
|
+
return False
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
import requests
|
5
|
+
from loguru import logger
|
6
|
+
|
7
|
+
from . import utils
|
8
|
+
|
9
|
+
|
10
|
+
def download(
|
11
|
+
request: dict,
|
12
|
+
file: dict,
|
13
|
+
chunks: bool = False,
|
14
|
+
iter_content: dict | None = None,
|
15
|
+
info: str | None = None
|
16
|
+
) -> bool:
|
17
|
+
"""下载文件"""
|
18
|
+
|
19
|
+
if utils.v_true(request, dict):
|
20
|
+
request_arguments = {"method": "GET", "stream": True, **request}
|
21
|
+
else:
|
22
|
+
return False
|
23
|
+
|
24
|
+
if utils.v_true(file, dict):
|
25
|
+
file_arguments = {"mode": "wb", **file}
|
26
|
+
else:
|
27
|
+
return False
|
28
|
+
|
29
|
+
if iter_content is not None and utils.v_true(iter_content, dict):
|
30
|
+
iter_content_arguments = {"chunk_size": 1024, **iter_content}
|
31
|
+
else:
|
32
|
+
iter_content_arguments = {"chunk_size": 1024}
|
33
|
+
|
34
|
+
info_prefix: str = "Download"
|
35
|
+
if utils.v_true(info, str):
|
36
|
+
info_prefix = f"Download {info}"
|
37
|
+
|
38
|
+
try:
|
39
|
+
|
40
|
+
logger.info(f'{info_prefix} ......')
|
41
|
+
|
42
|
+
response = requests.request(**request_arguments)
|
43
|
+
|
44
|
+
# # pylint: disable=W1514
|
45
|
+
with open(**file_arguments) as _file: # type: ignore
|
46
|
+
|
47
|
+
if utils.v_true(chunks, bool):
|
48
|
+
for _chunk in response.iter_content(**iter_content_arguments): # type: ignore
|
49
|
+
_file.write(_chunk)
|
50
|
+
else:
|
51
|
+
_file.write(response.content)
|
52
|
+
|
53
|
+
logger.success(f'{info_prefix} [success]')
|
54
|
+
|
55
|
+
return True
|
56
|
+
|
57
|
+
except Exception as e:
|
58
|
+
|
59
|
+
logger.error(f'{info_prefix} [failure]')
|
60
|
+
logger.exception(e)
|
61
|
+
return False
|
62
|
+
|
63
|
+
|
64
|
+
def response_json(data: Any = None, **kwargs) -> str | None:
|
65
|
+
"""解决字符编码问题: ensure_ascii=False"""
|
66
|
+
try:
|
67
|
+
return json.dumps(data, default=str, ensure_ascii=False, sort_keys=True, **kwargs)
|
68
|
+
except Exception as e:
|
69
|
+
logger.exception(e)
|
70
|
+
return None
|
@@ -28,7 +28,7 @@ class Mongo():
|
|
28
28
|
logger.success(f"{info} [success]")
|
29
29
|
return True
|
30
30
|
except Exception as e:
|
31
|
-
logger.error(f"{info} [
|
31
|
+
logger.error(f"{info} [failure]")
|
32
32
|
logger.exception(e)
|
33
33
|
return False
|
34
34
|
|
@@ -56,12 +56,12 @@ class Mongo():
|
|
56
56
|
# 插入多条数据
|
57
57
|
result = db_collection.insert_many(data)
|
58
58
|
else:
|
59
|
-
logger.error(f"{info} [
|
59
|
+
logger.error(f"{info} [failure]")
|
60
60
|
logger.error("Data type error")
|
61
61
|
return False
|
62
62
|
logger.success(f"{info} [success]")
|
63
63
|
return result
|
64
64
|
except Exception as e:
|
65
|
-
logger.error(f"{info} [
|
65
|
+
logger.error(f"{info} [failure]")
|
66
66
|
logger.exception(e)
|
67
67
|
return False
|
@@ -20,9 +20,10 @@ class Redis:
|
|
20
20
|
"""Initiation"""
|
21
21
|
if isinstance(arguments, str) and utils.v_true(arguments, str):
|
22
22
|
self.redis = RedisClient.from_url(arguments)
|
23
|
-
|
24
|
-
if isinstance(arguments, dict) and utils.v_true(arguments, dict):
|
23
|
+
elif isinstance(arguments, dict) and utils.v_true(arguments, dict):
|
25
24
|
self.redis = RedisClient.Redis(**arguments)
|
25
|
+
else:
|
26
|
+
pass
|
26
27
|
|
27
28
|
def connect_test(self) -> bool:
|
28
29
|
info = "Redis connect test"
|
@@ -32,7 +33,7 @@ class Redis:
|
|
32
33
|
logger.success(f"{info} [success]")
|
33
34
|
return True
|
34
35
|
except Exception as e:
|
35
|
-
logger.error(f"{info} [
|
36
|
+
logger.error(f"{info} [failure]")
|
36
37
|
logger.exception(e)
|
37
38
|
return False
|
38
39
|
|
@@ -48,6 +49,6 @@ class Redis:
|
|
48
49
|
logger.success(f"{info} [success]")
|
49
50
|
return True
|
50
51
|
except Exception as e:
|
51
|
-
logger.error(f"{info} [
|
52
|
+
logger.error(f"{info} [failure]")
|
52
53
|
logger.exception(e)
|
53
54
|
return False
|
@@ -1,12 +1,5 @@
|
|
1
1
|
"""发送邮件"""
|
2
2
|
# https://stackoverflow.com/questions/882712/sending-html-email-using-python
|
3
|
-
# pylint: disable=E0611
|
4
|
-
# pylint: disable=R0911
|
5
|
-
# pylint: disable=R0912
|
6
|
-
# pylint: disable=R0913
|
7
|
-
# pylint: disable=R0914
|
8
|
-
# pylint: disable=R0915
|
9
|
-
# pylint: disable=R1710
|
10
3
|
import smtplib
|
11
4
|
from email.header import Header
|
12
5
|
from email.mime.image import MIMEImage
|
@@ -1468,8 +1468,8 @@ def create_empty_file(
|
|
1468
1468
|
# 创建一个空文件
|
1469
1469
|
if v_true(debug, bool):
|
1470
1470
|
logger.info(f"file: {file}")
|
1471
|
-
# pylint: disable=R1732
|
1472
|
-
open(file,
|
1471
|
+
# pylint: disable=R1732
|
1472
|
+
open(file, "w", encoding="utf-8").close()
|
1473
1473
|
# 返回文件路径
|
1474
1474
|
return file
|
1475
1475
|
except Exception as e:
|
@@ -7,18 +7,13 @@ ezKit/bottle.py
|
|
7
7
|
ezKit/bottle_extensions.py
|
8
8
|
ezKit/cipher.py
|
9
9
|
ezKit/database.py
|
10
|
-
ezKit/files.py
|
11
10
|
ezKit/http.py
|
12
11
|
ezKit/mongo.py
|
13
|
-
ezKit/plots.py
|
14
|
-
ezKit/qywx.py
|
15
12
|
ezKit/redis.py
|
16
|
-
ezKit/reports.py
|
17
13
|
ezKit/sendemail.py
|
18
14
|
ezKit/token.py
|
19
15
|
ezKit/utils.py
|
20
16
|
ezKit/xftp.py
|
21
|
-
ezKit/zabbix.py
|
22
17
|
ezKit.egg-info/PKG-INFO
|
23
18
|
ezKit.egg-info/SOURCES.txt
|
24
19
|
ezKit.egg-info/dependency_links.txt
|
ezkit-1.7.8/README.md
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
# Python Easy Kit
|
2
|
-
|
3
|
-
## 代码规范
|
4
|
-
|
5
|
-
- [PEP 8 – Style Guide for Python Code](https://peps.python.org/pep-0008/)
|
6
|
-
- [PEP8 翻译](https://www.jianshu.com/p/78d76f85bd82)
|
7
|
-
- [PEP 8 -- Python 代码风格指南](https://github.com/kernellmd/Knowledge/blob/master/Translation/PEP%208%20%E4%B8%AD%E6%96%87%E7%BF%BB%E8%AF%91.md)
|
8
|
-
|
9
|
-
注释长度: 100
|
10
|
-
|
11
|
-
版本号说明: [PEP 440 – Version Identification and Dependency Specification](https://peps.python.org/pep-0440/)
|
12
|
-
|
13
|
-
配置文件格式: TOML
|
14
|
-
|
15
|
-
----------------------------------------------------------------------------------------------------
|
16
|
-
|
17
|
-
## 函数
|
18
|
-
|
19
|
-
- 明确 参数 的类型
|
20
|
-
- 尽量避免使用 *args 和 **kwargs
|
21
|
-
- 必须判断参数: 先判断参数是否为 None, 然后再判断参数类型
|
22
|
-
- 必须有返回值, 且明确返回值的类型(默认返回 bool 类型)
|
23
|
-
- 函数执行成功返回 True
|
24
|
-
- 执行执行失败返回 False
|
25
|
-
- 添加一个 debug 参数, 用于调试
|
26
|
-
- 如果 debug 为 True, 则输出相关信息, 否则一律不输出任何信息
|
27
|
-
- 必须有说明
|
28
|
-
- 必须用 `try ... except ...` 包裹
|
29
|
-
- 使用 loguru 输出信息 (不使用 print), 方便定位
|
30
|
-
|
31
|
-
```py
|
32
|
-
from loguru import logger
|
33
|
-
def func(debug: bool = False) -> bool:
|
34
|
-
try:
|
35
|
-
if debug is True:
|
36
|
-
logger.info("info ...")
|
37
|
-
# ...
|
38
|
-
return True
|
39
|
-
except Exception as e:
|
40
|
-
logger.exception(e)
|
41
|
-
return False
|
42
|
-
```
|
43
|
-
|
44
|
-
----------------------------------------------------------------------------------------------------
|
45
|
-
|
46
|
-
相关命令
|
47
|
-
|
48
|
-
```sh
|
49
|
-
# 打包
|
50
|
-
bash -x build.sh
|
51
|
-
|
52
|
-
# 上传
|
53
|
-
bash -x upload.sh
|
54
|
-
|
55
|
-
# 在线安装
|
56
|
-
pip install -U ezKit
|
57
|
-
|
58
|
-
# 离线安装
|
59
|
-
pip install -U ezKit-1.7.0.tar.gz
|
60
|
-
```
|
@@ -1,36 +0,0 @@
|
|
1
|
-
from typing import Callable
|
2
|
-
|
3
|
-
from . import bottle, utils
|
4
|
-
|
5
|
-
|
6
|
-
def enable_cors(fn: Callable) -> Callable:
|
7
|
-
"""
|
8
|
-
Bottle CORS
|
9
|
-
"""
|
10
|
-
"""
|
11
|
-
参考文档:
|
12
|
-
- https://stackoverflow.com/a/17262900
|
13
|
-
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
14
|
-
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
15
|
-
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
16
|
-
"""
|
17
|
-
def cors(*args, **kwargs):
|
18
|
-
bottle.response.headers['Access-Control-Allow-Headers'] = '*'
|
19
|
-
bottle.response.headers['Access-Control-Allow-Methods'] = '*'
|
20
|
-
bottle.response.headers['Access-Control-Allow-Origin'] = '*'
|
21
|
-
if bottle.request.method != 'OPTIONS':
|
22
|
-
return fn(*args, **kwargs)
|
23
|
-
return cors
|
24
|
-
|
25
|
-
def request_json() -> dict | None:
|
26
|
-
"""
|
27
|
-
Bottle Request JSON
|
28
|
-
"""
|
29
|
-
try:
|
30
|
-
data: dict = bottle.request.json
|
31
|
-
if utils.v_true(data, dict):
|
32
|
-
return data
|
33
|
-
else:
|
34
|
-
return None
|
35
|
-
except:
|
36
|
-
return None
|