ezKit 1.11.0__py3-none-any.whl → 1.11.2__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/_file.py +36 -0
- ezKit/qywx.py +216 -109
- ezKit/utils.py +9 -16
- {ezKit-1.11.0.dist-info → ezKit-1.11.2.dist-info}/METADATA +1 -1
- {ezKit-1.11.0.dist-info → ezKit-1.11.2.dist-info}/RECORD +8 -7
- {ezKit-1.11.0.dist-info → ezKit-1.11.2.dist-info}/LICENSE +0 -0
- {ezKit-1.11.0.dist-info → ezKit-1.11.2.dist-info}/WHEEL +0 -0
- {ezKit-1.11.0.dist-info → ezKit-1.11.2.dist-info}/top_level.txt +0 -0
ezKit/_file.py
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
from loguru import logger
|
2
|
+
|
3
|
+
from . import utils
|
4
|
+
|
5
|
+
|
6
|
+
def markdown_to_html(markdown_file: str, html_file: str, header_file: str = "markdown.html") -> bool:
|
7
|
+
"""Markdown to HTML"""
|
8
|
+
|
9
|
+
# Markdown to HTML
|
10
|
+
# 使用 MacDown 生成 HTML, 然后提取样式到 markdown.html
|
11
|
+
# pandoc 生成的 HTML 默认 max-width: 36em, 如果表格内容很长, 会导致表格样式难看
|
12
|
+
# 所以在 markdown.html 的 body{...} 中添加配置 max-width: unset, 解决内容过长的样式问题
|
13
|
+
# 所有 a 标签添加 text-decoration: none; 去除链接下划线
|
14
|
+
# pandoc --no-highlight -s --quiet -f markdown -t html -H markdown.html -o data.html data.md
|
15
|
+
|
16
|
+
info: str = "markdown to html"
|
17
|
+
|
18
|
+
logger.info(f"{info} ......")
|
19
|
+
|
20
|
+
try:
|
21
|
+
|
22
|
+
result = utils.shell(
|
23
|
+
f"pandoc --no-highlight -s --quiet -f markdown -t html -H {header_file} -o {html_file} {markdown_file}"
|
24
|
+
)
|
25
|
+
|
26
|
+
if result is None or result.returncode != 0:
|
27
|
+
logger.error(f"{info} [failure]")
|
28
|
+
return False
|
29
|
+
|
30
|
+
logger.success(f"{info} [success]")
|
31
|
+
return True
|
32
|
+
|
33
|
+
except Exception as e:
|
34
|
+
logger.error(f"{info} [failure]")
|
35
|
+
logger.exception(e)
|
36
|
+
return False
|
ezKit/qywx.py
CHANGED
@@ -1,10 +1,38 @@
|
|
1
1
|
"""企业微信"""
|
2
|
+
#
|
2
3
|
# 企业微信开发者中心
|
3
4
|
# https://developer.work.weixin.qq.com/
|
4
5
|
# https://developer.work.weixin.qq.com/document/path/90313 (全局错误码)
|
5
6
|
# 参考文档:
|
6
7
|
# https://www.gaoyuanqi.cn/python-yingyong-qiyewx/
|
7
8
|
# https://www.jianshu.com/p/020709b130d3
|
9
|
+
#
|
10
|
+
# 应用管理
|
11
|
+
# https://work.weixin.qq.com/wework_admin/frame#apps
|
12
|
+
# 自建 -> 创建应用
|
13
|
+
# https://work.weixin.qq.com/wework_admin/frame#apps/createApiApp
|
14
|
+
# 上传 Logo -> 应用名称 -> 选择部门 / 成员 -> 创建应用
|
15
|
+
#
|
16
|
+
# 服务端API
|
17
|
+
# https://developer.work.weixin.qq.com/document/path/90664
|
18
|
+
# 基本概念
|
19
|
+
# https://developer.work.weixin.qq.com/document/path/90665
|
20
|
+
# 企业ID:
|
21
|
+
# https://work.weixin.qq.com/wework_admin/frame#profile
|
22
|
+
# AgentId 和 Secret:
|
23
|
+
# 进入已创建的应用, 即可获取
|
24
|
+
#
|
25
|
+
# 应用管理 -> 应用 -> 开发者接口 -> 网页授权及JS-SDK
|
26
|
+
#
|
27
|
+
# 可作为应用OAuth2.0网页授权功能的回调域名
|
28
|
+
# 下载 配置可信域名需完成域名归属认证 的文件
|
29
|
+
# 保存到域名下
|
30
|
+
# 配置可信域名需完成域名归属认证 已验证
|
31
|
+
#
|
32
|
+
# 应用管理 -> 应用 -> 开发者接口 -> 企业可信IP
|
33
|
+
#
|
34
|
+
# 添加IP
|
35
|
+
#
|
8
36
|
import json
|
9
37
|
import time
|
10
38
|
|
@@ -17,150 +45,217 @@ from . import utils
|
|
17
45
|
class QYWX:
|
18
46
|
"""企业微信"""
|
19
47
|
|
20
|
-
|
21
|
-
|
22
|
-
agent_id: str | None = None
|
23
|
-
agent_secret: str | None = None
|
24
|
-
access_token: str | None = None
|
48
|
+
# API前缀
|
49
|
+
api_prefix = "https://qyapi.weixin.qq.com"
|
25
50
|
|
26
|
-
|
51
|
+
# 企业ID: https://developer.work.weixin.qq.com/document/path/90665#corpid
|
52
|
+
work_id: str = ""
|
53
|
+
|
54
|
+
# 应用ID: https://developer.work.weixin.qq.com/document/path/90665#agentid
|
55
|
+
agent_id: str = ""
|
56
|
+
|
57
|
+
# 应用Secret: https://developer.work.weixin.qq.com/document/path/90665#secret
|
58
|
+
agent_secret: str = ""
|
59
|
+
|
60
|
+
# Token: https://developer.work.weixin.qq.com/document/path/90665#access-token
|
61
|
+
access_token: str = ""
|
62
|
+
|
63
|
+
def __init__(self, work_id: str, agent_id: str, agent_secret: str):
|
27
64
|
"""Initiation"""
|
28
65
|
self.work_id = work_id
|
29
66
|
self.agent_id = agent_id
|
30
67
|
self.agent_secret = agent_secret
|
31
68
|
|
32
69
|
"""获取 Token"""
|
33
|
-
self.
|
70
|
+
self.get_access_token()
|
71
|
+
|
72
|
+
def get_access_token(self) -> bool:
|
73
|
+
"""获取Token"""
|
74
|
+
|
75
|
+
info: str = "获取 Token"
|
34
76
|
|
35
|
-
def getaccess_token(self) -> str | None:
|
36
77
|
try:
|
37
|
-
|
78
|
+
|
79
|
+
logger.info(f"{info} ......")
|
80
|
+
|
81
|
+
response = requests.get(f"{self.api_prefix}/cgi-bin/gettoken?corpid={self.work_id}&corpsecret={self.agent_secret}", timeout=10)
|
38
82
|
|
39
83
|
if response.status_code != 200:
|
40
|
-
|
41
|
-
return
|
84
|
+
logger.error(f"{info} [状态码错误]")
|
85
|
+
return False
|
42
86
|
|
43
87
|
result: dict = response.json()
|
44
|
-
self.access_token = result.get('access_token')
|
45
|
-
return result.get('access_token')
|
46
88
|
|
47
|
-
|
48
|
-
logger.exception(e)
|
49
|
-
return None
|
89
|
+
self.access_token = result.get("access_token", "")
|
50
90
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
self.getaccess_token()
|
55
|
-
response = requests.get(f"{self.url_prefix}/cgi-bin/agent/list?access_token={self.access_token}", timeout=10)
|
56
|
-
if response.status_code == 200:
|
57
|
-
response_data: dict = response.json()
|
58
|
-
if response_data.get('errcode') == 42001:
|
59
|
-
self.getaccess_token()
|
60
|
-
time.sleep(1)
|
61
|
-
self.get_agent_list()
|
62
|
-
return response_data
|
63
|
-
return response.text
|
64
|
-
except Exception as e:
|
65
|
-
logger.exception(e)
|
66
|
-
return None
|
91
|
+
if not utils.isTrue(self.access_token, str):
|
92
|
+
logger.error(f"{info} [失败]")
|
93
|
+
return False
|
67
94
|
|
68
|
-
|
69
|
-
|
70
|
-
try:
|
71
|
-
if self.access_token is None:
|
72
|
-
self.getaccess_token()
|
73
|
-
response = requests.get(f"{self.url_prefix}/cgi-bin/department/list?access_token={self.access_token}&id={eid}", timeout=10)
|
74
|
-
if response.status_code == 200:
|
75
|
-
response_data: dict = response.json()
|
76
|
-
if response_data.get('errcode') == 42001:
|
77
|
-
self.getaccess_token()
|
78
|
-
time.sleep(1)
|
79
|
-
self.get_department_list(eid)
|
80
|
-
return response_data
|
81
|
-
return response.text
|
82
|
-
except Exception as e:
|
83
|
-
logger.exception(e)
|
84
|
-
return None
|
95
|
+
logger.success(f"{info} [成功]")
|
96
|
+
return True
|
85
97
|
|
86
|
-
def get_user_list(self, eid: str | None = None) -> dict | str | None:
|
87
|
-
"""eid: Enterprise ID"""
|
88
|
-
try:
|
89
|
-
if self.access_token is None:
|
90
|
-
self.getaccess_token()
|
91
|
-
response = requests.get(f"{self.url_prefix}/cgi-bin/user/list?access_token={self.access_token}&department_id={eid}", timeout=10)
|
92
|
-
if response.status_code == 200:
|
93
|
-
response_data: dict = response.json()
|
94
|
-
if response_data.get('errcode') == 42001:
|
95
|
-
self.getaccess_token()
|
96
|
-
time.sleep(1)
|
97
|
-
self.get_user_list(eid)
|
98
|
-
return response_data
|
99
|
-
return response.text
|
100
98
|
except Exception as e:
|
99
|
+
logger.success(f"{info} [失败]")
|
101
100
|
logger.exception(e)
|
101
|
+
return False
|
102
|
+
|
103
|
+
# def get_agent_list(self) -> dict | str | None:
|
104
|
+
# try:
|
105
|
+
# if not utils.isTrue(self.access_token, str):
|
106
|
+
# self.get_access_token()
|
107
|
+
# response = requests.get(f"{self.api_prefix}/cgi-bin/agent/list?access_token={self.access_token}", timeout=10)
|
108
|
+
# if response.status_code == 200:
|
109
|
+
# response_data: dict = response.json()
|
110
|
+
# if response_data.get('errcode') == 42001:
|
111
|
+
# self.get_access_token()
|
112
|
+
# time.sleep(1)
|
113
|
+
# self.get_agent_list()
|
114
|
+
# return response_data
|
115
|
+
# return response.text
|
116
|
+
# except Exception as e:
|
117
|
+
# logger.exception(e)
|
118
|
+
# return None
|
119
|
+
|
120
|
+
# def get_department_list(self, eid: str | None = None) -> dict | str | None:
|
121
|
+
# """eid: Enterprise ID"""
|
122
|
+
# try:
|
123
|
+
# if self.access_token is None:
|
124
|
+
# self.get_access_token()
|
125
|
+
# response = requests.get(f"{self.api_prefix}/cgi-bin/department/list?access_token={self.access_token}&id={eid}", timeout=10)
|
126
|
+
# if response.status_code == 200:
|
127
|
+
# response_data: dict = response.json()
|
128
|
+
# if response_data.get('errcode') == 42001:
|
129
|
+
# self.get_access_token()
|
130
|
+
# time.sleep(1)
|
131
|
+
# self.get_department_list(eid)
|
132
|
+
# return response_data
|
133
|
+
# return response.text
|
134
|
+
# except Exception as e:
|
135
|
+
# logger.exception(e)
|
136
|
+
# return None
|
137
|
+
|
138
|
+
# def get_user_list(self, eid: str | None = None) -> dict | str | None:
|
139
|
+
# """eid: Enterprise ID"""
|
140
|
+
# try:
|
141
|
+
# if self.access_token is None:
|
142
|
+
# self.get_access_token()
|
143
|
+
# response = requests.get(f"{self.api_prefix}/cgi-bin/user/list?access_token={self.access_token}&department_id={eid}", timeout=10)
|
144
|
+
# if response.status_code == 200:
|
145
|
+
# response_data: dict = response.json()
|
146
|
+
# if response_data.get('errcode') == 42001:
|
147
|
+
# self.get_access_token()
|
148
|
+
# time.sleep(1)
|
149
|
+
# self.get_user_list(eid)
|
150
|
+
# return response_data
|
151
|
+
# return response.text
|
152
|
+
# except Exception as e:
|
153
|
+
# logger.exception(e)
|
154
|
+
# return None
|
155
|
+
|
156
|
+
def get_user_id_by_mobile(self, mobile: str) -> dict | None:
|
157
|
+
"""根据电话号码获取用户ID"""
|
158
|
+
|
159
|
+
info: str = f"根据电话号码获取用户ID: {mobile}"
|
160
|
+
|
161
|
+
if not utils.check_arguments([(mobile, str, "mobile")]):
|
162
|
+
logger.error(f"{info} [错误]")
|
102
163
|
return None
|
103
164
|
|
104
|
-
def get_user_id_by_mobile(self, mobile: str | None = None) -> dict | str | None:
|
105
165
|
try:
|
106
|
-
|
107
|
-
|
166
|
+
|
167
|
+
logger.info(f"{info} ......")
|
168
|
+
|
169
|
+
if not utils.isTrue(self.access_token, str):
|
170
|
+
self.get_access_token()
|
171
|
+
|
108
172
|
json_string = json.dumps({'mobile': mobile})
|
109
|
-
response = requests.post(f"{self.url_prefix}/cgi-bin/user/getuserid?access_token={self.access_token}", data=json_string, timeout=10)
|
110
|
-
if response.status_code == 200:
|
111
|
-
response_data: dict = response.json()
|
112
|
-
if response_data.get('errcode') == 42001:
|
113
|
-
self.getaccess_token()
|
114
|
-
time.sleep(1)
|
115
|
-
self.get_user_id_by_mobile(mobile)
|
116
|
-
return response_data
|
117
|
-
return response.text
|
118
|
-
except Exception as e:
|
119
|
-
logger.exception(e)
|
120
|
-
return None
|
121
173
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
174
|
+
response = requests.post(f"{self.api_prefix}/cgi-bin/user/getuserid?access_token={self.access_token}", data=json_string, timeout=10)
|
175
|
+
|
176
|
+
if response.status_code != 200:
|
177
|
+
logger.error(f"{info} [接口请求错误]")
|
178
|
+
return None
|
179
|
+
|
180
|
+
response_data: dict = response.json()
|
181
|
+
|
182
|
+
if response_data.get('errcode') == 42001:
|
183
|
+
self.get_access_token()
|
184
|
+
time.sleep(1)
|
185
|
+
self.get_user_id_by_mobile(mobile)
|
186
|
+
|
187
|
+
logger.success(f"{info} [成功]")
|
188
|
+
|
189
|
+
return response_data
|
190
|
+
|
191
|
+
# return response.text
|
192
|
+
|
136
193
|
except Exception as e:
|
194
|
+
logger.error(f"{info} [失败]")
|
137
195
|
logger.exception(e)
|
138
196
|
return None
|
139
197
|
|
198
|
+
# def get_user_info(self, eid: str | None = None) -> dict | str | None:
|
199
|
+
# """eid: Enterprise ID"""
|
200
|
+
# try:
|
201
|
+
# if self.access_token is None:
|
202
|
+
# self.get_access_token()
|
203
|
+
# response = requests.get(f"{self.api_prefix}/cgi-bin/user/get?access_token={self.access_token}&userid={eid}", timeout=10)
|
204
|
+
# if response.status_code == 200:
|
205
|
+
# response_data: dict = response.json()
|
206
|
+
# if response_data.get('errcode') == 42001:
|
207
|
+
# self.get_access_token()
|
208
|
+
# time.sleep(1)
|
209
|
+
# self.get_user_info(eid)
|
210
|
+
# return response_data
|
211
|
+
# return response.text
|
212
|
+
# except Exception as e:
|
213
|
+
# logger.exception(e)
|
214
|
+
# return None
|
215
|
+
|
140
216
|
def send_message_by_mobile(self, mobile: str | list, message: str) -> bool:
|
141
217
|
"""发送消息"""
|
142
218
|
|
143
219
|
# 参考文档:
|
144
220
|
# https://developer.work.weixin.qq.com/document/path/90235
|
145
221
|
|
222
|
+
info: str = "发送消息"
|
223
|
+
|
224
|
+
if not utils.check_arguments([(mobile, (str, list), "mobile"), (message, str, "message")]):
|
225
|
+
logger.error(f"{info} [失败]")
|
226
|
+
return False
|
227
|
+
|
146
228
|
try:
|
147
|
-
if self.access_token is None:
|
148
|
-
self.getaccess_token()
|
149
229
|
|
150
|
-
|
230
|
+
logger.info(f"{info} ......")
|
151
231
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
case True if isinstance(mobile, str) and utils.isTrue(mobile, str):
|
156
|
-
users.append(mobile)
|
157
|
-
case _:
|
232
|
+
if not utils.isTrue(self.access_token, str):
|
233
|
+
if not self.get_access_token():
|
234
|
+
logger.error(f"{info} [失败]")
|
158
235
|
return False
|
159
236
|
|
237
|
+
users: list = []
|
238
|
+
|
239
|
+
if isinstance(mobile, str) and utils.isTrue(mobile, str):
|
240
|
+
users.append(mobile)
|
241
|
+
elif isinstance(mobile, list) and utils.isTrue(mobile, list):
|
242
|
+
users += mobile
|
243
|
+
else:
|
244
|
+
logger.error(f"{info} [电话号码错误]")
|
245
|
+
return False
|
246
|
+
|
160
247
|
for user in users:
|
248
|
+
|
249
|
+
logger.info(f"{info} [用户 {user}]")
|
250
|
+
|
161
251
|
user_object = self.get_user_id_by_mobile(user)
|
162
252
|
|
163
|
-
if not isinstance(user_object, dict):
|
253
|
+
if not (isinstance(user_object, dict) and utils.isTrue(user_object, dict)):
|
254
|
+
logger.error(f"{info} [获取用户ID错误: {user}]")
|
255
|
+
continue
|
256
|
+
|
257
|
+
if user_object.get("errcode", -1) != 0 or user_object.get("errmsg", "") != "ok":
|
258
|
+
logger.error(f"{user_object.get('errcode')}: {user_object.get('errmsg')}")
|
164
259
|
continue
|
165
260
|
|
166
261
|
json_dict = {
|
@@ -173,17 +268,29 @@ class QYWX:
|
|
173
268
|
'enable_duplicate_check': 0,
|
174
269
|
'duplicate_check_interval': 1800
|
175
270
|
}
|
271
|
+
|
176
272
|
json_string = json.dumps(json_dict)
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
273
|
+
|
274
|
+
response = requests.post(f"{self.api_prefix}/cgi-bin/message/send?access_token={self.access_token}", data=json_string, timeout=10)
|
275
|
+
|
276
|
+
if response.status_code != 200:
|
277
|
+
logger.error(f"{info} [发送消息失败: {user}]")
|
278
|
+
continue
|
279
|
+
|
280
|
+
response_data: dict = response.json()
|
281
|
+
|
282
|
+
if response_data.get('errcode') == 42001:
|
283
|
+
self.get_access_token()
|
284
|
+
time.sleep(1)
|
285
|
+
self.send_message_by_mobile(mobile, message)
|
286
|
+
|
287
|
+
logger.success(f"{info} [成功: 用户 {user}]")
|
288
|
+
|
289
|
+
logger.success(f"{info} [完成]")
|
184
290
|
|
185
291
|
return True
|
186
292
|
|
187
293
|
except Exception as e:
|
294
|
+
logger.error(f"{info} [失败]")
|
188
295
|
logger.exception(e)
|
189
296
|
return False
|
ezKit/utils.py
CHANGED
@@ -418,26 +418,19 @@ def list_print_by_step(
|
|
418
418
|
|
419
419
|
try:
|
420
420
|
|
421
|
-
# result: list = []
|
422
|
-
|
423
|
-
# if len(data) <= step:
|
424
|
-
# result.append(data)
|
425
|
-
# else:
|
426
|
-
# data_list = list_split(data, step, debug=debug)
|
427
|
-
# if data_list is None or isTrue(data_list, list) is False:
|
428
|
-
# return False
|
429
|
-
# result = data_list
|
430
|
-
|
431
|
-
# for item in result:
|
432
|
-
# print(*item, sep=separator)
|
433
|
-
|
434
|
-
# return True
|
435
|
-
|
436
421
|
# 打印
|
437
422
|
for i, v in enumerate(data):
|
423
|
+
|
438
424
|
if i > 0 and i % step == 0:
|
439
425
|
print()
|
440
|
-
|
426
|
+
|
427
|
+
# print(v, end=separator)
|
428
|
+
|
429
|
+
# 每行最后一个 或者 所有数据最后一个, 不打印分隔符
|
430
|
+
if ((i % step) == (step - 1)) or ((i + 1) == len(data)):
|
431
|
+
print(v, end='')
|
432
|
+
else:
|
433
|
+
print(v, end=separator)
|
441
434
|
|
442
435
|
print()
|
443
436
|
|
@@ -1,18 +1,19 @@
|
|
1
1
|
ezKit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
ezKit/_file.py,sha256=0qRZhwYuagTgTGrhm-tzAMvEQT4HTJA_xZKqF2bo0ho,1207
|
2
3
|
ezKit/bottle.py,sha256=usKK1wVaZw4_D-4VwMYmOIc8jtz4TrpM30nck59HMFw,180178
|
3
4
|
ezKit/bottle_extensions.py,sha256=3reEQVZuHklXTl6r7F8kiBFFPb0RaAGc3mYJJnrMDjQ,1129
|
4
5
|
ezKit/cipher.py,sha256=0T_StbjiNI4zgrjVgcfU-ffKgu1waBA9UDudAnqFcNM,2896
|
5
6
|
ezKit/database.py,sha256=r5YNoEzeOeVTlEWI99xXtHTmPZ73_DopS8DTzZk8Lts,12432
|
6
7
|
ezKit/http.py,sha256=ysXzqXFi9zmuVKINbYGwmf9Q5xDVW_DZWrSh6HSVq8M,1800
|
7
8
|
ezKit/mongo.py,sha256=l3jRMmoGrTm16OG4daSCn0JLU1nbYAmTtHokwjLXzoA,2390
|
8
|
-
ezKit/qywx.py,sha256=
|
9
|
+
ezKit/qywx.py,sha256=GKwcx_L3WCcWEMZuuMpqdAy9ubqSu2RoxndxkkAYRtQ,10301
|
9
10
|
ezKit/redis.py,sha256=tdiqfizPYQQTIUumkJGUJsJVlv0zVTSTYGQN0QutYs4,1963
|
10
11
|
ezKit/sendemail.py,sha256=tRXCsJm_RfTJ9xEWe_lTQ5kOs2JxHGPXvq0oWA7prq0,7263
|
11
12
|
ezKit/token.py,sha256=HKREyZj_T2S8-aFoFIrBXTaCKExQq4zE66OHXhGHqQg,1750
|
12
|
-
ezKit/utils.py,sha256=
|
13
|
+
ezKit/utils.py,sha256=a2RiwOjO83Wi4GmyBRLI1UreaVgNLL66Snbq0HnI37c,42501
|
13
14
|
ezKit/xftp.py,sha256=XyIdr_2rxRVLqPofG6fIYWhAMVsFwTyp46dg5P9FLW4,7774
|
14
|
-
ezKit-1.11.
|
15
|
-
ezKit-1.11.
|
16
|
-
ezKit-1.11.
|
17
|
-
ezKit-1.11.
|
18
|
-
ezKit-1.11.
|
15
|
+
ezKit-1.11.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
16
|
+
ezKit-1.11.2.dist-info/METADATA,sha256=O6yYp94ImOfIjj7pLEWeFsCl1PDBeJNk9nPgme9iOAs,191
|
17
|
+
ezKit-1.11.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
18
|
+
ezKit-1.11.2.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
|
19
|
+
ezKit-1.11.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|