pykitool 0.0.1__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.
@@ -0,0 +1,518 @@
1
+ import base64
2
+ import hashlib
3
+ import json
4
+ import os
5
+ import platform
6
+ import random
7
+ import re
8
+ import secrets
9
+ import string
10
+ import subprocess
11
+ import time
12
+ import uuid
13
+ from datetime import datetime
14
+ from pathlib import Path
15
+ from typing import Any, Dict, List, Optional, Union
16
+
17
+ from loguru import logger
18
+
19
+ from pykitool.base.enums import Platform
20
+ from pykitool.utils import cbruntime
21
+
22
+ # 预编译正则表达式(模块级别)
23
+ _HTTP_PATTERN = re.compile(r"^https?://")
24
+ _NUMBER_PATTERN = re.compile(r"(\d+)")
25
+
26
+ # 获取随机 User-Agent
27
+ _ua_instance = None
28
+
29
+ # ================================ Common 通用功能 ================================
30
+
31
+
32
+ # 判断是否为调试模式
33
+ def is_debug() -> bool:
34
+ return cbruntime.get_arg(["--reload", "--debug"], False)
35
+
36
+
37
+ # 判断是否为 HTTP/HTTPS 链接
38
+ def is_http(url: str) -> bool:
39
+ if not url:
40
+ return False
41
+ return _HTTP_PATTERN.match(url) is not None
42
+
43
+
44
+ # ================================ Device 设备信息 ================================
45
+
46
+
47
+ # 判断是否为 Windows 系统
48
+ def is_windows() -> bool:
49
+ return platform.system().lower() == Platform.Window.value
50
+
51
+
52
+ # 判断是否为 Linux 系统
53
+ def is_linux() -> bool:
54
+ return platform.system().lower() == Platform.Linux.value
55
+
56
+
57
+ # 判断是否为 Mac 系统
58
+ def is_mac() -> bool:
59
+ return platform.system().lower() == Platform.Mac.value
60
+
61
+
62
+ # 生成指定范围内的随机数
63
+ def get_random(start: int = 10000000, end: int = 99999999) -> int:
64
+ return random.randint(start, end)
65
+
66
+
67
+ # ================================ Git 版本信息 ================================
68
+
69
+
70
+ def get_git_info():
71
+
72
+ git_info = {"branch": "unknown", "date": "unknown", "hash": "unknown"}
73
+
74
+ try:
75
+ repo_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
76
+
77
+ # 获取分支名
78
+ result = subprocess.run(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=repo_path, capture_output=True, text=True, timeout=5)
79
+ if result.returncode == 0:
80
+ git_info["branch"] = result.stdout.strip()
81
+
82
+ # 获取最后提交时间
83
+ result = subprocess.run(["git", "log", "-1", "--format=%ci"], cwd=repo_path, capture_output=True, text=True, timeout=5)
84
+ if result.returncode == 0:
85
+ git_info["date"] = result.stdout.strip()
86
+
87
+ # 获取短 commit hash
88
+ result = subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=repo_path, capture_output=True, text=True, timeout=5)
89
+ if result.returncode == 0:
90
+ git_info["hash"] = result.stdout.strip()
91
+ except Exception as e:
92
+ print(f"Warning: Failed to get git info - {e}")
93
+
94
+ return git_info
95
+
96
+
97
+ # ================================ Json 数据操作 ================================
98
+
99
+
100
+ # 验证字符串是否为有效的 JSON 格式
101
+ def is_json(data: str) -> bool:
102
+ if not data or not isinstance(data, str):
103
+ return False
104
+ # 快速检查:JSON 必须以 {、[ 开头或是基本类型
105
+ data_stripped = data.strip()
106
+ if not data_stripped:
107
+ return False
108
+ first_char = data_stripped[0]
109
+ if first_char not in ("{", "[", '"', "t", "f", "n", "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
110
+ return False
111
+ try:
112
+ json.loads(data)
113
+ return True
114
+ except (ValueError, TypeError):
115
+ return False
116
+
117
+
118
+ # 解析 JSON 字符串
119
+ def load_json(data: str, default: Any = None) -> Any:
120
+ try:
121
+ return json.loads(data)
122
+ except (ValueError, TypeError) as e:
123
+ logger.error(f"Failed to parse JSON: {str(e)}")
124
+ return default
125
+
126
+
127
+ # 从文件加载 JSON 数据
128
+ def load_json_file(path: Union[str, Path], default: Any = None) -> Any:
129
+ try:
130
+ path_obj = Path(path) if isinstance(path, str) else path
131
+ if not path_obj.exists():
132
+ return default
133
+ with open(path_obj, "r", encoding="utf-8") as file:
134
+ return json.load(file)
135
+ except (ValueError, IOError, OSError) as e:
136
+ logger.error(f"Failed to load JSON file {path}: {str(e)}")
137
+ return default
138
+
139
+
140
+ # 将数据转换为 JSON 字符串(紧凑格式)
141
+ def to_json(data: Any) -> str:
142
+ return json.dumps(
143
+ data,
144
+ ensure_ascii=False,
145
+ separators=(",", ":"),
146
+ default=lambda o: o.model_dump() if hasattr(o, "model_dump") else str(o),
147
+ )
148
+
149
+
150
+ # 将数据转换为格式化的 JSON 字符串
151
+ def to_json_pretty(data: Any, indent: int = 4, sort_keys: bool = False) -> str:
152
+ return json.dumps(
153
+ data,
154
+ ensure_ascii=False,
155
+ default=lambda o: o.model_dump() if hasattr(o, "model_dump") else str(o),
156
+ indent=indent,
157
+ sort_keys=sort_keys,
158
+ )
159
+
160
+
161
+ # ================================ Encrypt 加密解密 ================================
162
+
163
+
164
+ # 加密数据
165
+ def encrypt(data: Any, password: str = "0123456789") -> Optional[str]:
166
+ try:
167
+ raw = json.dumps(data).encode("utf-8")
168
+ key = hashlib.sha256(password.encode()).digest()
169
+ encrypted = bytes([b ^ key[i % len(key)] for i, b in enumerate(raw)])
170
+ return base64.b64encode(encrypted).decode("utf-8")
171
+ except Exception as e:
172
+ logger.error(f"Encryption failed: {str(e)}")
173
+ return None
174
+
175
+
176
+ # 解密数据
177
+ def decrypt(enc_data: str, password: str = "0123456789") -> Any:
178
+ try:
179
+ encrypted = base64.b64decode(enc_data)
180
+ key = hashlib.sha256(password.encode()).digest()
181
+ decrypted = bytes([b ^ key[i % len(key)] for i, b in enumerate(encrypted)])
182
+ return json.loads(decrypted.decode("utf-8"))
183
+ except Exception as e:
184
+ logger.error(f"Decryption failed: {str(e)}")
185
+ return None
186
+
187
+
188
+ # ================================ String 字符串操作 ================================
189
+
190
+
191
+ # 生成终端超链接
192
+ def str_hyperlink(url: str, text: str) -> str:
193
+ ESC = "\033"
194
+ return f"{ESC}]8;;{url}{ESC}\\{text}{ESC}]8;;{ESC}\\"
195
+
196
+
197
+ # 生成随机密码
198
+ def str_password(length: int = 6) -> str:
199
+ chars = string.ascii_letters + string.digits # 字母+数字
200
+ while True:
201
+ password = "".join(secrets.choice(chars) for _ in range(length))
202
+ # 确保至少包含一个字母和一个数字
203
+ if any(c.isdigit() for c in password) and any(c.isalpha() for c in password):
204
+ return password
205
+
206
+
207
+ # 计算字符串的 MD5 哈希值
208
+ def str_to_md5(text: str) -> str:
209
+ md5_hash = hashlib.md5()
210
+ md5_hash.update(text.encode("utf-8"))
211
+ return md5_hash.hexdigest()
212
+
213
+
214
+ # 计算字符串的 MD5 哈希值(截取指定位数)
215
+ def str_to_md5_short(text: str, length: int = 6) -> str:
216
+ return str_to_md5(text)[:length]
217
+
218
+
219
+ # 生成 UUID 字符串(无连字符)
220
+ def uuid_str() -> str:
221
+ return str(uuid.uuid4()).replace("-", "")
222
+
223
+
224
+ # 生成数字型 UUID(时间戳+随机数)
225
+ def uuid_numeric() -> str:
226
+ return str(int(time.time() * 1000)) + str(random.randint(1000, 9999))
227
+
228
+
229
+ # 生成随机 User-Agent
230
+ def random_ua() -> str:
231
+ global _ua_instance
232
+ if _ua_instance is None:
233
+ from fake_useragent import UserAgent
234
+
235
+ _ua_instance = UserAgent()
236
+ return _ua_instance.random
237
+
238
+
239
+ # 生成指定范围内的随机数
240
+ def random_int(start: int = 10000000, end: int = 99999999) -> int:
241
+ return random.randint(start, end)
242
+
243
+
244
+ # ================================ Time 时间操作 ================================
245
+
246
+
247
+ # 获取当前时间
248
+ def get_current_time(format: str = "%Y-%m-%d %H:%M:%S", as_string: bool = True) -> Union[str, datetime]:
249
+ now = datetime.now()
250
+ if as_string:
251
+ return now.strftime(format)
252
+ return now
253
+
254
+
255
+ # 将时间戳格式化为本地时间字符串
256
+ def format_to_localtime(ts: Union[int, float] = 0, format: str = "%Y-%m-%d %H:%M:%S") -> Union[str, int]:
257
+ try:
258
+ if ts == 0:
259
+ return "Never"
260
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ts))
261
+ except Exception as e:
262
+ logger.error(f"Format to localtime failed: {str(e)}")
263
+ return 0
264
+
265
+
266
+ # 计算距离指定时间的剩余天数
267
+ def time_interval_days(end_time: str, now_time: Optional[str] = None, use_http: bool = False, url: str = "https://www.baidu.com") -> int:
268
+ fmt = "%Y-%m-%d %H:%M:%S"
269
+ end_dt = datetime.strptime(end_time, fmt)
270
+
271
+ if now_time:
272
+ now_dt = datetime.strptime(now_time, fmt)
273
+ else:
274
+ now_dt = datetime.now()
275
+
276
+ delta = end_dt - now_dt
277
+ return delta.days if delta.days >= 0 else -1
278
+
279
+
280
+ # 将 cron 表达式的小时字段从 CST(东八区)转换为 UTC(-8h),仅处理固定数字小时
281
+ def cst_to_utc(expr: str) -> str:
282
+ parts = expr.strip().split()
283
+ if len(parts) != 5:
284
+ return expr
285
+ minute, hour, day, month, weekday = parts
286
+ if hour.isdigit():
287
+ utc_hour = (int(hour) - 8) % 24
288
+ return " ".join([minute, str(utc_hour), day, month, weekday])
289
+ return expr
290
+
291
+
292
+ # ================================ List 列表操作 ================================
293
+
294
+
295
+ # 根据字段值查找列表中的元素
296
+ def find_list_item_by_field(items: List[Union[Dict[str, Any], Any]], field: str, value: Any) -> Optional[Union[Dict[str, Any], Any]]:
297
+ for item in items:
298
+ if isinstance(item, dict):
299
+ if item.get(field) == value:
300
+ return item
301
+ else:
302
+ if getattr(item, field, None) == value:
303
+ return item
304
+ return None
305
+
306
+
307
+ # 查找字段值在指定集合中的所有元素
308
+ def find_list_item_by_value_in_set(array: List[Dict[str, Any]], field: str, values_set: set) -> List[Dict[str, Any]]:
309
+ return [item for item in array if item.get(field) in values_set]
310
+
311
+
312
+ # 对字符串列表排序(数字优先,字母其次)
313
+ def sort_by_array(items: List[str]) -> List[str]:
314
+ def sort_key(x: str) -> tuple[Union[int, float], str]:
315
+ match = _NUMBER_PATTERN.match(x)
316
+ num = int(match.group(1)) if match else float("inf")
317
+ return (num, x.lower())
318
+
319
+ return sorted(items, key=sort_key)
320
+
321
+
322
+ # 对字典按键排序(数字优先,字母其次)
323
+ def sort_by_dict(d: Dict[str, Any]) -> Dict[str, Any]:
324
+ def sort_key(k: str) -> tuple[Union[int, float], str]:
325
+ match = _NUMBER_PATTERN.match(k)
326
+ num = int(match.group(1)) if match else float("inf")
327
+ return (num, k.lower())
328
+
329
+ sorted_items = sorted(d.items(), key=lambda item: sort_key(item[0]))
330
+ return dict(sorted_items)
331
+
332
+
333
+ # ================================ 调用示例 ================================
334
+
335
+ if __name__ == "__main__":
336
+
337
+ # ==================== Common 通用功能示例 ====================
338
+
339
+ # 判断是否为调试模式
340
+ # result = is_debug()
341
+ # logger.info(f"Is debug mode: {result}")
342
+
343
+ # 判断是否为 HTTP/HTTPS 链接
344
+ # result = is_http("https://example.com")
345
+ # logger.info(f"Is HTTP URL: {result}")
346
+
347
+ # ==================== Network 网络与语言示例 ====================
348
+
349
+ # 获取系统语言环境
350
+ # result = get_locale()
351
+ # logger.info(f"System locale: {result}")
352
+
353
+ # 根据语言代码获取完整的语言环境标识
354
+ # result = get_locale_by_lang("zh", "zh-CN")
355
+ # logger.info(f"Locale by lang: {result}")
356
+
357
+ # 解析语言标签,返回语言和地区
358
+ # lang, region = parse_locale("zh-CN")
359
+ # logger.info(f"Parse locale: lang={lang}, region={region}")
360
+
361
+ # 检测文本的语言类型
362
+ # result = detect_language("Hello World")
363
+ # logger.info(f"Detect language: {result}")
364
+
365
+ # 智能拼接文本(根据语言决定是否添加空格)
366
+ # result = smart_join(["Hello", "World"])
367
+ # logger.info(f"Smart join: {result}")
368
+
369
+ # ==================== Device 设备信息示例 ====================
370
+
371
+ # 判断操作系统类型
372
+ # logger.info(f"Is Windows: {is_windows()}")
373
+ # logger.info(f"Is Linux: {is_linux()}")
374
+ # logger.info(f"Is Mac: {is_mac()}")
375
+
376
+ # 生成指定范围内的随机数
377
+ # result = get_random(1, 100)
378
+ # logger.info(f"Random number: {result}")
379
+
380
+ # 设置随机种子,确保结果可复现
381
+ # seed = set_random_seed(42)
382
+ # logger.info(f"Set random seed: {seed}")
383
+
384
+ # 获取可用的 CPU 核心数
385
+ # count = cpu_available_count()
386
+ # logger.info(f"Available CPU count: {count}")
387
+
388
+ # 判断 CUDA 是否可用
389
+ # result = cuda_is_available()
390
+ # logger.info(f"CUDA available: {result}")
391
+
392
+ # 清空 CUDA 显存缓存
393
+ # cuda_memory_clear()
394
+ # logger.info("CUDA memory cleared")
395
+
396
+ # 获取计算设备(CPU 或 GPU)
397
+ # result = device()
398
+ # logger.info(f"Device: {result}")
399
+
400
+ # ==================== Json JSON操作示例 ====================
401
+
402
+ # 验证字符串是否为有效的 JSON 格式
403
+ # result = is_json('{"key": "value"}')
404
+ # logger.info(f"Is JSON: {result}")
405
+
406
+ # 解析 JSON 字符串
407
+ # result = load_json('{"key": "value"}')
408
+ # logger.info(f"Load JSON: {result}")
409
+
410
+ # 从文件加载 JSON 数据
411
+ # result = load_json_file("config.json", default={})
412
+ # logger.info(f"Load JSON file: {result}")
413
+
414
+ # 将数据转换为 JSON 字符串(紧凑格式)
415
+ # data = {"name": "张三", "age": 30, "city": "北京"}
416
+ # result = to_json(data)
417
+ # logger.info(f"To JSON: {result}")
418
+
419
+ # 将数据转换为格式化的 JSON 字符串
420
+ # result = to_json_pretty(data, indent=2)
421
+ # logger.info(f"To JSON pretty:\n{result}")
422
+
423
+ # ==================== Encrypt 加密解密示例 ====================
424
+
425
+ # 加密和解密数据
426
+ # original_data = {"username": "admin", "password": "123456"}
427
+ # encrypted = encrypt(original_data)
428
+ # logger.info(f"Encrypted: {encrypted}")
429
+ # decrypted = decrypt(encrypted)
430
+ # logger.info(f"Decrypted: {decrypted}")
431
+
432
+ # ==================== String 字符串操作示例 ====================
433
+
434
+ # 生成终端超链接
435
+ # result = str_hyperlink("https://github.com", "GitHub")
436
+ # logger.info(f"Hyperlink: {result}")
437
+
438
+ # 生成随机密码
439
+ # result = str_password(8)
440
+ # logger.info(f"Random password: {result}")
441
+
442
+ # 计算字符串的 MD5 哈希值
443
+ # result = str_to_md5("Hello World")
444
+ # logger.info(f"MD5: {result}")
445
+
446
+ # 计算字符串的 MD5 哈希值(截取指定位数)
447
+ # result = str_to_md5_short("Hello World", 8)
448
+ # logger.info(f"MD5 short: {result}")
449
+
450
+ # 生成 UUID 字符串
451
+ # result = uuid_str()
452
+ # logger.info(f"UUID string: {result}")
453
+
454
+ # 生成数字型 UUID
455
+ # result = uuid_numeric()
456
+ # logger.info(f"UUID numeric: {result}")
457
+
458
+ # 生成随机 User-Agent
459
+ # result = random_ua()
460
+ # logger.info(f"Random UA: {result}")
461
+
462
+ # ==================== Time 时间操作示例 ====================
463
+
464
+ # 获取当前时间
465
+ # result = get_current_time()
466
+ # logger.info(f"Current time: {result}")
467
+
468
+ # 获取当前时间(datetime 对象)
469
+ # result = get_current_time(as_string=False)
470
+ # logger.info(f"Current time (datetime): {result}")
471
+
472
+ # 通过 HTTP 请求获取网络时间
473
+ # result = get_http_time()
474
+ # logger.info(f"HTTP time: {result}")
475
+
476
+ # 将时间戳格式化为本地时间字符串
477
+ # result = format_to_localtime(1704067200)
478
+ # logger.info(f"Format timestamp: {result}")
479
+
480
+ # 格式化为 SRT 字幕时间格式
481
+ # result = format_to_srttime(125.5, "s")
482
+ # logger.info(f"SRT time: {result}")
483
+
484
+ # 将 SRT 时间格式转换为秒数
485
+ # result = time_to_ss("00:00:14,420")
486
+ # logger.info(f"SRT to seconds: {result}")
487
+
488
+ # 将 SRT 时间格式转换为毫秒数
489
+ # result = time_to_ms("00:00:14,420")
490
+ # logger.info(f"SRT to milliseconds: {result}")
491
+
492
+ # 计算距离指定时间的剩余天数
493
+ # end_time = "2025-12-31 23:59:59"
494
+ # result = time_interval_days(end_time)
495
+ # logger.info(f"Days until end: {result}")
496
+
497
+ # ==================== List 列表操作示例 ====================
498
+
499
+ # 根据字段值查找列表中的元素
500
+ # items = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
501
+ # result = find_list_item_by_field(items, "id", 2)
502
+ # logger.info(f"Find by field: {result}")
503
+
504
+ # 查找字段值在指定集合中的所有元素
505
+ # result = find_list_item_by_value_in_set(items, "id", {1, 3})
506
+ # logger.info(f"Find by value in set: {result}")
507
+
508
+ # 对字符串列表排序(数字优先,字母其次)
509
+ # arr = ["item10", "item2", "item1", "itemA", "item20"]
510
+ # result = sort_by_array(arr)
511
+ # logger.info(f"Sort array: {result}")
512
+
513
+ # 对字典按键排序(数字优先,字母其次)
514
+ # d = {"key10": "v10", "key2": "v2", "key1": "v1", "keyA": "vA"}
515
+ # result = sort_by_dict(d)
516
+ # logger.info(f"Sort dict: {result}")
517
+
518
+ pass
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: pykitool
3
+ Version: 0.0.1
4
+ Author: xiesx
5
+ Project-URL: Homepage, https://github.com/xiesx123/pykitool
6
+ Project-URL: Documentation, https://wgp520.github.io/hutool-python
7
+ Project-URL: Repository, https://github.com/xiesx123/pykitool
8
+ Project-URL: Issues, https://github.com/xiesx123/pykitool/issues
9
+ Project-URL: Changelog, https://github.com/xiesx123/pykitool/blob/master/docs/changelog.md
10
+ Keywords: toolkit,tools,utils,helper
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: asyncio==4.0.0
25
+ Requires-Dist: fake-useragent>=2.0.0
26
+ Requires-Dist: hutool-python>=1.1.1
27
+ Requires-Dist: loguru>=0.7.3
28
+ Requires-Dist: psutil>=7.2.2
29
+ Requires-Dist: pydantic>=2.10.6
30
+ Requires-Dist: requests-cache>=1.3.2
31
+ Requires-Dist: sqlalchemy>=2.0.51
32
+ Requires-Dist: sqlmodel>=0.0.29
33
+ Requires-Dist: starlette>=0.44.0
34
+ Requires-Dist: tqdm>=4.68.3
35
+ Provides-Extra: dev
36
+ Requires-Dist: pytest>=8.0; extra == "dev"
@@ -0,0 +1,21 @@
1
+ pykitool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pykitool/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ pykitool/base/cache.py,sha256=BAld3v7dlidzco63DE6C7lGrMxWj4_s4rxWUt-LIYAU,12049
4
+ pykitool/base/enums.py,sha256=Qtvjqw7Mgrn7z8zZCz2l08XMVRI3AmNSR4K6nOZ4lGE,2689
5
+ pykitool/base/exception.py,sha256=HbWc78b3BlGUMPQpXNf09tqJSuurv4Tth1hYOJ3u2kU,212
6
+ pykitool/base/response.py,sha256=uRiEMMO7q-jyqWhauskBkqLdmCvsio4JM-bM4ztAlq8,2449
7
+ pykitool/base/tlog.py,sha256=LVndIXawjvlaaHy8q3IMmjveJ8QRPgucD2c62I-QTK4,6831
8
+ pykitool/sqliter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ pykitool/sqliter/exception.py,sha256=JBwIcwF_lWyxQYjVVnWoauZTz1QCNrkDgRdoduewep4,896
10
+ pykitool/sqliter/middleware.py,sha256=B8fPvyvtIJI5QZvV4OqwxVxONwzbhBgFHj4OlXOmf4g,2915
11
+ pykitool/sqliter/plus.py,sha256=Z4ZQ2vZ7HEuoGe47BJinEmWf8TBBUFr7xMdxkUIBTik,3696
12
+ pykitool/sqliter/repo.py,sha256=EQyX3zgGPajmfFEJEPZVImVDU99SFpes9h5kVJ7g0sw,7660
13
+ pykitool/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ pykitool/utils/cbfile.py,sha256=5EQEgRNlgdgMaSADibYiuGUbl5uBlZPN8pwt3LFpFug,24521
15
+ pykitool/utils/cbrequest.py,sha256=aa0Gh-2xwSqjruhv_x0UwFBh_I2aBCX1B1XpEImJIQA,16008
16
+ pykitool/utils/cbruntime.py,sha256=u7MdawuvKwH4RzrItFQlkmrd0Kp6MgAcbt-C31o2NeI,30659
17
+ pykitool/utils/cbutils.py,sha256=R3ludgfKtLK6t9dG6WXVoVsuf7ePtG-PKYqjKJFHaBQ,16962
18
+ pykitool-0.0.1.dist-info/METADATA,sha256=y9CDFG1ApoTLhpSjOw71wkPQeLJgAsrcYWKyZKW106Q,1526
19
+ pykitool-0.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
20
+ pykitool-0.0.1.dist-info/top_level.txt,sha256=hGytFFLb2K2eleUxmYmrBRH1Db2Qhsh4FgGPfgo5dIQ,9
21
+ pykitool-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ pykitool