ezKit 1.7.7__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.
Files changed (33) hide show
  1. {ezkit-1.7.7/ezKit.egg-info → ezkit-1.8.0}/PKG-INFO +1 -1
  2. ezkit-1.8.0/README.md +1 -0
  3. ezkit-1.8.0/ezKit/__init__.py +0 -0
  4. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/bottle.py +7 -2
  5. ezkit-1.8.0/ezKit/bottle_extensions.py +32 -0
  6. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/cipher.py +11 -10
  7. ezkit-1.8.0/ezKit/database.py +204 -0
  8. ezkit-1.8.0/ezKit/http.py +70 -0
  9. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/mongo.py +24 -21
  10. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/redis.py +19 -16
  11. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/sendemail.py +1 -10
  12. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/token.py +11 -12
  13. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/utils.py +8 -6
  14. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit/xftp.py +2 -2
  15. {ezkit-1.7.7 → ezkit-1.8.0/ezKit.egg-info}/PKG-INFO +1 -1
  16. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit.egg-info/SOURCES.txt +0 -5
  17. {ezkit-1.7.7 → ezkit-1.8.0}/setup.py +1 -1
  18. ezkit-1.7.7/README.md +0 -234
  19. ezkit-1.7.7/ezKit/__init__.py +0 -1
  20. ezkit-1.7.7/ezKit/bottle_extensions.py +0 -36
  21. ezkit-1.7.7/ezKit/database.py +0 -168
  22. ezkit-1.7.7/ezKit/files.py +0 -348
  23. ezkit-1.7.7/ezKit/http.py +0 -71
  24. ezkit-1.7.7/ezKit/plots.py +0 -155
  25. ezkit-1.7.7/ezKit/qywx.py +0 -173
  26. ezkit-1.7.7/ezKit/reports.py +0 -274
  27. ezkit-1.7.7/ezKit/zabbix.py +0 -737
  28. {ezkit-1.7.7 → ezkit-1.8.0}/LICENSE +0 -0
  29. {ezkit-1.7.7 → ezkit-1.8.0}/MANIFEST.in +0 -0
  30. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit.egg-info/dependency_links.txt +0 -0
  31. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit.egg-info/requires.txt +0 -0
  32. {ezkit-1.7.7 → ezkit-1.8.0}/ezKit.egg-info/top_level.txt +0 -0
  33. {ezkit-1.7.7 → ezkit-1.8.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.7.7
3
+ Version: 1.8.0
4
4
  Summary: Easy Kit
5
5
  Author: septvean
6
6
  Author-email: septvean@gmail.com
ezkit-1.8.0/README.md ADDED
@@ -0,0 +1 @@
1
+ # Python Easy Kit
File without changes
@@ -17,7 +17,7 @@ from __future__ import print_function
17
17
  import sys
18
18
 
19
19
  __author__ = 'Marcel Hellkamp'
20
- __version__ = '0.13.1'
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
- if __name__ == '__main__': # pragma: no coverage
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
@@ -1,9 +1,9 @@
1
- '''
1
+ """
2
2
  https://docs.python.org/3.10/library/hashlib.html
3
3
  https://www.pycrypto.org/
4
4
  https://stackoverflow.com/a/21928790
5
5
  pip install pycryptodome
6
- '''
6
+ """
7
7
  import base64
8
8
  import hashlib
9
9
 
@@ -12,7 +12,8 @@ from Crypto.Cipher import AES
12
12
  from loguru import logger
13
13
 
14
14
 
15
- class AESCipher(object):
15
+ class AESCipher:
16
+ """AESCipher"""
16
17
 
17
18
  def __init__(self, key: str = 'vB7DoRm9C2Kd', algorithm: str = 'sha256'):
18
19
 
@@ -40,10 +41,10 @@ class AESCipher(object):
40
41
  self.key = hashlib.sha3_384(key.encode()).digest()
41
42
  case True if algorithm == 'sha3_512':
42
43
  self.key = hashlib.sha3_512(key.encode()).digest()
43
- case True if algorithm == 'shake_128':
44
- self.key = hashlib.shake_128(key.encode()).digest()
45
- case True if algorithm == 'shake_256':
46
- self.key = hashlib.shake_256(key.encode()).digest()
44
+ # case True if algorithm == 'shake_128':
45
+ # self.key = hashlib.shake_128(key.encode()).digest()
46
+ # case True if algorithm == 'shake_256':
47
+ # self.key = hashlib.shake_256(key.encode()).digest()
47
48
  case _:
48
49
  self.key = hashlib.sha256(key.encode()).digest()
49
50
 
@@ -59,10 +60,10 @@ class AESCipher(object):
59
60
 
60
61
  def decrypt(self, enc: str) -> str | None:
61
62
  try:
62
- enc = base64.b64decode(enc)
63
- iv = enc[:AES.block_size]
63
+ enc_bytes = base64.b64decode(enc)
64
+ iv = enc_bytes[:AES.block_size]
64
65
  cipher = AES.new(self.key, AES.MODE_CBC, iv)
65
- return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
66
+ return self._unpad(cipher.decrypt(enc_bytes[AES.block_size:])).decode('utf-8')
66
67
  except Exception as e:
67
68
  logger.exception(e)
68
69
  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
@@ -1,6 +1,7 @@
1
1
  """MongoDB"""
2
2
  from loguru import logger
3
3
  from pymongo import MongoClient
4
+ from pymongo.collection import Collection
4
5
 
5
6
  from . import utils
6
7
 
@@ -10,39 +11,41 @@ class Mongo():
10
11
 
11
12
  client = MongoClient()
12
13
 
13
- def close(self):
14
+ def close(self) -> bool:
14
15
  """client close"""
15
16
  try:
16
17
  self.client.close()
18
+ return True
17
19
  except Exception as e:
18
20
  logger.exception(e)
21
+ return False
19
22
 
20
- def connect_test(self, debug: bool = False):
21
- """client connect test"""
22
- info = 'MongoDB连接测试'
23
+ def connect_test(self) -> bool:
24
+ info = "MongoDB connect test"
23
25
  try:
24
- logger.info(f'{info}[执行]')
26
+ logger.info(f"{info} ......")
25
27
  self.client.server_info()
26
- logger.success(f'{info}[成功]')
28
+ logger.success(f"{info} [success]")
27
29
  return True
28
30
  except Exception as e:
29
- logger.error(f'{info}[失败]')
30
- if utils.v_true(debug, bool):
31
- logger.exception(e)
31
+ logger.error(f"{info} [failure]")
32
+ logger.exception(e)
32
33
  return False
33
34
 
34
- def collection(self, database, name):
35
- """client collection"""
36
- return self.client[database][name]
35
+ def collection(self, database: str, name: str) -> Collection | None:
36
+ try:
37
+ return self.client[database][name]
38
+ except Exception as e:
39
+ logger.exception(e)
40
+ return None
37
41
 
38
- def collection_insert(self, database, collection, data, drop=None):
39
- """client collection insert"""
42
+ def collection_insert(self, database, collection, data, drop: bool = False):
40
43
  db_collection = self.client[database][collection]
41
- info = '插入数据'
44
+ info = "MongoDB collection insert"
42
45
  try:
43
- logger.info(f'{info}[执行]')
46
+ logger.info(f"{info} ......")
44
47
  # 是否删除 collection
45
- if drop is True:
48
+ if utils.v_true(drop, bool):
46
49
  # 删除 collection
47
50
  db_collection.drop()
48
51
  # 插入数据
@@ -53,12 +56,12 @@ class Mongo():
53
56
  # 插入多条数据
54
57
  result = db_collection.insert_many(data)
55
58
  else:
56
- logger.error(f'{info}[失败]')
57
- logger.error('数据类型错误')
59
+ logger.error(f"{info} [failure]")
60
+ logger.error("Data type error")
58
61
  return False
59
- logger.success(f'{info}[成功]')
62
+ logger.success(f"{info} [success]")
60
63
  return result
61
64
  except Exception as e:
62
- logger.error(f'{info}[失败]')
65
+ logger.error(f"{info} [failure]")
63
66
  logger.exception(e)
64
67
  return False
@@ -1,10 +1,12 @@
1
+ """Redis"""
1
2
  import redis as RedisClient
2
3
  from loguru import logger
3
4
 
4
5
  from . import utils
5
6
 
6
7
 
7
- class Redis(object):
8
+ class Redis:
9
+ """Redis"""
8
10
 
9
11
  # https://redis.readthedocs.io/en/stable/_modules/redis/client.html#Redis
10
12
  # https://github.com/redis/redis-py#client-classes-redis-and-strictredis
@@ -14,38 +16,39 @@ class Redis(object):
14
16
  # 这里修改以下参数: host, port, socket_timeout, socket_connect_timeout, charset
15
17
  redis = RedisClient.Redis()
16
18
 
17
- def __init__(self, arguments=None):
18
- '''Initiation'''
19
- if utils.v_true(arguments, str):
19
+ def __init__(self, arguments: str | dict):
20
+ """Initiation"""
21
+ if isinstance(arguments, str) and utils.v_true(arguments, str):
20
22
  self.redis = RedisClient.from_url(arguments)
21
- elif utils.v_true(arguments, dict):
23
+ elif isinstance(arguments, dict) and utils.v_true(arguments, dict):
22
24
  self.redis = RedisClient.Redis(**arguments)
23
25
  else:
24
26
  pass
25
27
 
26
- def connect_test(self):
27
- info = 'Redis连接测试'
28
+ def connect_test(self) -> bool:
29
+ info = "Redis connect test"
28
30
  try:
29
- logger.info(f'{info}......')
31
+ logger.info(f"{info} ......")
30
32
  self.redis.ping()
31
- logger.success(f'{info}[成功]')
33
+ logger.success(f"{info} [success]")
32
34
  return True
33
35
  except Exception as e:
34
- logger.error(f'{info}[失败]')
36
+ logger.error(f"{info} [failure]")
35
37
  logger.exception(e)
36
38
  return False
37
39
 
38
- def flush(self, all=None):
39
- info = 'Redis数据清理'
40
+ def flush(self, flushall: bool = False) -> bool:
41
+ info = "Redis flush"
40
42
  try:
41
- logger.info(f'{info}......')
42
- if all == True:
43
+ if utils.v_true(flushall, bool):
44
+ logger.info(f"{info} all ......")
43
45
  self.redis.flushall()
44
46
  else:
47
+ logger.info(f"{info} db ......")
45
48
  self.redis.flushdb()
46
- logger.success(f'{info}[成功]')
49
+ logger.success(f"{info} [success]")
47
50
  return True
48
51
  except Exception as e:
49
- logger.error(f'{info}[失败]')
52
+ logger.error(f"{info} [failure]")
50
53
  logger.exception(e)
51
54
  return False
@@ -1,14 +1,5 @@
1
- """
2
- 发送邮件
3
- """
1
+ """发送邮件"""
4
2
  # https://stackoverflow.com/questions/882712/sending-html-email-using-python
5
- # pylint: disable=E0611
6
- # pylint: disable=R0911
7
- # pylint: disable=R0912
8
- # pylint: disable=R0913
9
- # pylint: disable=R0914
10
- # pylint: disable=R0915
11
- # pylint: disable=R1710
12
3
  import smtplib
13
4
  from email.header import Header
14
5
  from email.mime.image import MIMEImage
@@ -4,33 +4,32 @@ from typing import Any
4
4
 
5
5
  from loguru import logger
6
6
 
7
- from .cipher import AESCipher
8
- from .utils import datetime_now, datetime_offset, datetime_string_to_datetime, datetime_to_string, v_true
7
+ from . import cipher, utils
9
8
 
10
9
 
11
10
  def generate_token(key: str = 'Fc0zXCmGKd7tPu6W', timeout: int = 3600, data: Any = None) -> (str | None):
12
11
  try:
13
- now = datetime_now()
12
+ now = utils.datetime_now()
14
13
 
15
14
  if now is None:
16
15
  return None
17
16
 
18
- offset = datetime_offset(now, seconds=+timeout)
17
+ offset = utils.datetime_offset(now, seconds=+timeout)
19
18
 
20
19
  if offset is None:
21
20
  return None
22
21
 
23
22
  source = json.dumps(
24
23
  obj={
25
- "datetime": datetime_to_string(offset),
24
+ "datetime": utils.datetime_to_string(offset),
26
25
  "data": data
27
26
  },
28
27
  default=str
29
28
  )
30
29
 
31
- cipher = AESCipher(key=key, algorithm='sha256')
30
+ aes_cipher = cipher.AESCipher(key=key, algorithm='sha256')
32
31
 
33
- return cipher.encrypt(source)
32
+ return aes_cipher.encrypt(source)
34
33
 
35
34
  except Exception as e:
36
35
  logger.exception(e)
@@ -39,19 +38,19 @@ def generate_token(key: str = 'Fc0zXCmGKd7tPu6W', timeout: int = 3600, data: Any
39
38
 
40
39
  def parsing_token(token_string: str, key: str = 'Fc0zXCmGKd7tPu6W') -> (dict | None):
41
40
  try:
42
- if v_true(token_string, str) is False:
41
+ if utils.v_true(token_string, str) is False:
43
42
  return None
44
43
 
45
- cipher = AESCipher(key=key, algorithm='sha256')
44
+ aes_cipher = cipher.AESCipher(key=key, algorithm='sha256')
46
45
 
47
- target = cipher.decrypt(token_string)
46
+ target = aes_cipher.decrypt(token_string)
48
47
 
49
48
  if target is None:
50
49
  return None
51
50
 
52
51
  source: dict = json.loads(target)
53
52
 
54
- source['datetime'] = datetime_string_to_datetime(source['datetime'])
53
+ source['datetime'] = utils.datetime_string_to_datetime(source['datetime'])
55
54
 
56
55
  return source
57
56
 
@@ -68,7 +67,7 @@ def certify_token(token_string: str, key: str = 'Fc0zXCmGKd7tPu6W') -> bool:
68
67
  if result is None:
69
68
  return False
70
69
 
71
- if result.get('datetime') < datetime_now(): # type: ignore
70
+ if result.get('datetime') < utils.datetime_now(): # type: ignore
72
71
  return False
73
72
 
74
73
  return True
@@ -1,6 +1,4 @@
1
- """
2
- Python Utils
3
- """
1
+ """Utils"""
4
2
  import csv
5
3
  import datetime
6
4
  import hashlib
@@ -49,6 +47,10 @@ def v_true(
49
47
  List list/tuple/set []/()/{}
50
48
  Dictionary dict {}
51
49
 
50
+ 查看变量类型: type(x)
51
+
52
+ 判断变量类型: isinstance(x, str)
53
+
52
54
  函数使用 callable(func) 判断
53
55
  """
54
56
 
@@ -623,7 +625,7 @@ def dict_remove_key(
623
625
  data: dict,
624
626
  key: str,
625
627
  debug: bool = False
626
- ) -> None | dict:
628
+ ) -> dict | None:
627
629
  """dict remove key"""
628
630
  try:
629
631
  data_copy: dict = deepcopy(data)
@@ -1466,8 +1468,8 @@ def create_empty_file(
1466
1468
  # 创建一个空文件
1467
1469
  if v_true(debug, bool):
1468
1470
  logger.info(f"file: {file}")
1469
- # pylint: disable=R1732,disable=W1514
1470
- open(file, 'w').close()
1471
+ # pylint: disable=R1732
1472
+ open(file, "w", encoding="utf-8").close()
1471
1473
  # 返回文件路径
1472
1474
  return file
1473
1475
  except Exception as e: