lantool 0.1.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 (78) hide show
  1. lantool-0.1.0/.gitignore +40 -0
  2. lantool-0.1.0/CHANGELOG.md +147 -0
  3. lantool-0.1.0/LICENSE +21 -0
  4. lantool-0.1.0/PKG-INFO +252 -0
  5. lantool-0.1.0/README.md +194 -0
  6. lantool-0.1.0/docs/getting-started.md +526 -0
  7. lantool-0.1.0/docs/index.md +21 -0
  8. lantool-0.1.0/docs/publish.md +346 -0
  9. lantool-0.1.0/docs/usage.md +401 -0
  10. lantool-0.1.0/pyproject.toml +76 -0
  11. lantool-0.1.0/src/lantool/__init__.py +261 -0
  12. lantool-0.1.0/src/lantool/__main__.py +70 -0
  13. lantool-0.1.0/src/lantool/_emoji_data.py +628 -0
  14. lantool-0.1.0/src/lantool/_fonts.py +74 -0
  15. lantool-0.1.0/src/lantool/_http_data.py +157 -0
  16. lantool-0.1.0/src/lantool/_optional.py +42 -0
  17. lantool-0.1.0/src/lantool/barcodex.py +95 -0
  18. lantool-0.1.0/src/lantool/bytesize.py +138 -0
  19. lantool-0.1.0/src/lantool/chardata.py +150 -0
  20. lantool-0.1.0/src/lantool/collx.py +98 -0
  21. lantool-0.1.0/src/lantool/convert.py +174 -0
  22. lantool-0.1.0/src/lantool/cronx.py +230 -0
  23. lantool-0.1.0/src/lantool/decorators.py +227 -0
  24. lantool-0.1.0/src/lantool/diffx.py +81 -0
  25. lantool-0.1.0/src/lantool/encoding.py +430 -0
  26. lantool-0.1.0/src/lantool/env.py +133 -0
  27. lantool-0.1.0/src/lantool/errors.py +57 -0
  28. lantool-0.1.0/src/lantool/files.py +165 -0
  29. lantool-0.1.0/src/lantool/formatx.py +144 -0
  30. lantool-0.1.0/src/lantool/hashing.py +181 -0
  31. lantool-0.1.0/src/lantool/ids.py +171 -0
  32. lantool-0.1.0/src/lantool/imagex.py +326 -0
  33. lantool-0.1.0/src/lantool/jsonx.py +165 -0
  34. lantool-0.1.0/src/lantool/jwtx.py +83 -0
  35. lantool-0.1.0/src/lantool/log.py +407 -0
  36. lantool-0.1.0/src/lantool/misc.py +185 -0
  37. lantool-0.1.0/src/lantool/password.py +127 -0
  38. lantool-0.1.0/src/lantool/pdfx.py +367 -0
  39. lantool-0.1.0/src/lantool/py.typed +0 -0
  40. lantool-0.1.0/src/lantool/qrcodex.py +111 -0
  41. lantool-0.1.0/src/lantool/retryx.py +131 -0
  42. lantool-0.1.0/src/lantool/security.py +441 -0
  43. lantool-0.1.0/src/lantool/text.py +314 -0
  44. lantool-0.1.0/src/lantool/times.py +240 -0
  45. lantool-0.1.0/src/lantool/validator.py +132 -0
  46. lantool-0.1.0/src/lantool/webdata.py +159 -0
  47. lantool-0.1.0/src/lantool/xmlix.py +141 -0
  48. lantool-0.1.0/src/lantool/yamlix.py +103 -0
  49. lantool-0.1.0/tests/__init__.py +0 -0
  50. lantool-0.1.0/tests/conftest.py +24 -0
  51. lantool-0.1.0/tests/test_bytesize.py +205 -0
  52. lantool-0.1.0/tests/test_chardata.py +118 -0
  53. lantool-0.1.0/tests/test_collx.py +86 -0
  54. lantool-0.1.0/tests/test_concurrency.py +218 -0
  55. lantool-0.1.0/tests/test_convert.py +176 -0
  56. lantool-0.1.0/tests/test_cronx.py +298 -0
  57. lantool-0.1.0/tests/test_decorators.py +190 -0
  58. lantool-0.1.0/tests/test_diffx.py +70 -0
  59. lantool-0.1.0/tests/test_encoding.py +372 -0
  60. lantool-0.1.0/tests/test_env.py +133 -0
  61. lantool-0.1.0/tests/test_errors.py +45 -0
  62. lantool-0.1.0/tests/test_files.py +161 -0
  63. lantool-0.1.0/tests/test_formatx.py +232 -0
  64. lantool-0.1.0/tests/test_hashing.py +114 -0
  65. lantool-0.1.0/tests/test_ids.py +194 -0
  66. lantool-0.1.0/tests/test_init.py +52 -0
  67. lantool-0.1.0/tests/test_jsonx.py +173 -0
  68. lantool-0.1.0/tests/test_log.py +486 -0
  69. lantool-0.1.0/tests/test_main.py +111 -0
  70. lantool-0.1.0/tests/test_misc.py +225 -0
  71. lantool-0.1.0/tests/test_optional.py +1466 -0
  72. lantool-0.1.0/tests/test_password.py +120 -0
  73. lantool-0.1.0/tests/test_retry.py +168 -0
  74. lantool-0.1.0/tests/test_text.py +281 -0
  75. lantool-0.1.0/tests/test_times.py +223 -0
  76. lantool-0.1.0/tests/test_validator.py +211 -0
  77. lantool-0.1.0/tests/test_webdata.py +157 -0
  78. lantool-0.1.0/tests/test_xmlix.py +115 -0
@@ -0,0 +1,40 @@
1
+ # Python 构建产物
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ build/
6
+ dist/
7
+ *.egg-info/
8
+ *.egg
9
+ .eggs/
10
+
11
+ # 虚拟环境
12
+ .venv/
13
+ venv/
14
+ env/
15
+
16
+ # 测试与覆盖率
17
+ .pytest_cache/
18
+ .coverage
19
+ coverage.xml
20
+ htmlcov/
21
+
22
+ # Lint 缓存
23
+ .ruff_cache/
24
+ .mypy_cache/
25
+
26
+ # 日志文件
27
+ logs/
28
+ *.log
29
+
30
+ # IDE
31
+ .idea/
32
+ .vscode/
33
+ *.swp
34
+
35
+ # 操作系统
36
+ .DS_Store
37
+ Thumbs.db
38
+
39
+ # Claude 本地配置
40
+ .claude/
@@ -0,0 +1,147 @@
1
+ # Changelog
2
+
3
+ 本文件记录 lantool 的所有重要变更。格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
+ 版本遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
5
+
6
+ ## [Unreleased]
7
+
8
+ ### Security
9
+
10
+ - `curl` 生成命令中 URL/method/timeout 未转义的 shell 注入面(现全参数 POSIX 单引号转义,
11
+ method 白名单校验、timeout 类型校验、json/data 互斥)
12
+
13
+ ### Fixed
14
+
15
+ - `python -m lantool` 在管道/重定向场景下按系统区域编码(如中文 Windows 的 GBK)写出,
16
+ UTF-8 终端与文件中出现中文乱码;现仅对非交互流统一为 UTF-8(交互终端保持原编码,
17
+ 作为库函数调用 `main()` 时不对进程标准流做任何改动)
18
+
19
+ - `dir(lantool)` 保留 `__file__`/`__path__` 等标准模块属性,同时提供全部懒加载导出名
20
+ - `ascii_table` 的 NUL 字符改用可见 `\x00` 表示,与其他不可打印字符保持一致
21
+ - `hash_file` 对 `chunk_size < 1` 静默产出空数据哈希,现显式抛 `ValidationError`
22
+ - `compact_xml` 丢弃混合内容文本(词间空格及纯内联元素间换行等可见文本被压缩掉);
23
+ 现仅删除可识别的缩进空白与叶节点首尾空白,无法确定用途的混合内容空白原样保留;
24
+ 深层格式化/压缩的递归异常统一为 `ParseError`
25
+ - Cron 星期域区间含 7(`0-7`/`5-7` 等)违反 crontab(5) 语义的解析错误;拒绝空步长,
26
+ 闰日可跨越多年寻找下次运行时间,无法匹配时的错误说明改为 datetime 可表示范围
27
+ - 校验器锚定接受尾随换行(`is_email`/`is_phone_cn`)、非 str 输入静默通过或泄漏裸异常
28
+ (`is_ipv4`/`is_ipv6`/`is_url`/`is_id_card_cn`,畸形 IPv6 URL 现返回 False);
29
+ URL 拒绝原始控制空白与非法端口,手机号/身份证仅接受 ASCII 数字
30
+ - `to_timestamp`/`str_to_timestamp` 负时间戳向零截断(应向下取整);平台时间转换异常统一为
31
+ `ParseError`;`human_duration` 非法输入泄漏裸 `ValueError`
32
+ - `to_bool` 对 float 与 int 不对称;`to_bool(NaN/inf)` 静默转 True(现返回 default);
33
+ `to_datetime` 不支持含毫秒/时区的 ISO 8601 字符串;超大整数在 `to_float`/`to_datetime`
34
+ 中不再绕过失败回退约定
35
+ - `get_env` 的默认值现在与环境值一样经过类型转换,转换失败(含数值溢出)统一抛
36
+ `ValidationError`,不再返回未经转换的对象
37
+ - `retry` 正抖动可能突破 `max_delay`;`rate_limit` 时间戳读取移入窗口锁内,避免并发入队
38
+ 乱序导致错误限流
39
+ - `curl(params=...)` 在 URL 含 fragment 时把查询参数拼到 `#` 后,现仅更新 query 部分
40
+ - `convert_base` 静默接受下划线分隔与全角数字(`int()` 解析怪癖泄漏)
41
+ - `timing`/`suppress_errors` 未适配 async 函数(计时错误/异常抑制静默失效)
42
+ - YAML 解析错误(`YAMLError`)、条形码数据非法、JWT 签发/校验参数错误、
43
+ DES/3DES 短密文、RSA 非 UTF-8 明文等泄漏原生异常,统一纳入 `LanToolError` 体系
44
+ - 日志滚动:归档目录存在杂散文件时 `doRollover` 崩溃丢日志;跨午夜归档改按内容所属日命名;
45
+ 严格识别完整归档文件名,过期与同天限额清理不再删除同前缀手工备份或受其序号干扰
46
+ - 图片水印定位未补偿 textbbox 偏移(贴边);原地压缩(dst == src)统计失真;
47
+ 截断图片的延迟解码错误统一为 `ValidationError`,非方形源图生成完整方形 ICO 档位,
48
+ 透明图片转 JPEG 先按白底合成,数值参数统一校验
49
+ - PDF 文字水印不再以不透明白图遮挡原页面,按每页尺寸生成透明水印;页树延迟解析、
50
+ 零页文档、页码与字号等非法输入统一纳入 `ValidationError`
51
+ - 二维码超容量、条形码 SVG 非法 XML 控制字符及 PNG 缺少 Pillow 时的原生异常,
52
+ 现转为明确的校验或可选依赖异常
53
+ - `format_number`/`format_currency` 的十进制字符串与 `format_percent` 的大整数不再经
54
+ float 或受限 Decimal context 丢精度;`convert_size` 避免中间乘法把有限结果溢出为 inf;
55
+ `human_size` 小数科学计数法往返断裂
56
+ - JSON 拒绝 RFC 非法的 `NaN`/`Infinity`(显式 `allow_nan=True` 也不能重新启用),
57
+ 深层输入的递归异常统一为解析/校验错误;`validate` 在超出解析深度时返回 False
58
+ - `java_fields` 拒绝 Java 关键字、字面量与单下划线;`natural_sort` 不再对上标数字泄漏
59
+ `ValueError`;`count_chars` 统一 CR/LF 换行语义;diff 行列表不再注入伪空行
60
+ - BMI 极端有限数值的算术溢出/下溢统一为 `ValidationError`
61
+ - `hashing` 全入口标注 `usedforsecurity=False`(FIPS 环境下 md5/sha1 非安全用途可用)
62
+ - 原子写在 POSIX 下覆盖文件后权限收窄为 0600;异常清理始终独占 fd 所有权并统一关闭,
63
+ 避免误关其他线程已复用的文件描述符
64
+ - `format_number`/`format_currency`/`format_percent` 对 NaN/Infinity(含 Decimal 实例与
65
+ 数字字符串)静默输出伪结果,现统一抛 `ValidationError`
66
+ - `get_env_float` 接受 `nan`/`inf` 等非有限值、`get_env_json` 接受 `NaN`/`Infinity`
67
+ 非标准 JSON,现在分别回退默认值与按非法 JSON 处理
68
+ - `get_logger("")` 返回并配置 root logger(违背库不触碰 root logger 的承诺),现抛
69
+ `ValidationError`;名称按 Windows 可移植文件名规则校验(路径分隔符、盘符相对路径、
70
+ NUL 等控制字符、保留设备名、首尾空白),避免写出 `log_dir` 或每次 emit 静默丢日志;
71
+ 滚动参数补齐整数类型校验(浮点值会在滚动清理阶段触发被 logging 吞掉的 `TypeError`)
72
+ - `cron_next_run` 在 `base=datetime.max` 等起点越界场景泄漏原生 `OverflowError`,
73
+ 现统一为 `ParseError`
74
+ - `compress_image`/水印函数改用 Pillow 扩展名注册表解析输出格式:未知扩展名与
75
+ 只读格式(如 `.psd`/`.xpm`,不在 `Image.SAVE` 中)不再泄漏 `KeyError`/`ValueError`,
76
+ 目标无扩展名时沿用源图格式,水印保存统一显式指定格式
77
+ - `pdf_merge` 空文件列表静默生成 0 页 PDF,现抛 `ValidationError`;
78
+ `images_to_pdf` 中途读取失败时关闭已打开的帧,避免资源泄漏
79
+ - `base64_decode_bytes` 非文本输入泄漏原生 `TypeError`,现统一为 `EncodeError`
80
+ - `convert_size`/`human_size` 接受布尔值及 NaN/Infinity,现显式校验为 `ValidationError`
81
+ - `natural_sort` 的数字段先规范化为 ASCII 数字串(支持全角/阿拉伯-印度等 Unicode 数字),
82
+ 再按“长度 + 去前导零数字串”比较:既保持数值序,也不再触发 Python 的整数字符串转换
83
+ 位数上限
84
+ - `to_timestamp` 字符串入参未容忍首尾空白(与 `str_to_timestamp` 不一致);现在先按 fmt
85
+ 原样解析,失败后再去空白重试,保留 fmt 自带字面空白的用法
86
+ - `curl(params=...)` 序列值未按重复键展开,现与常见 HTTP 客户端编码一致
87
+ - `rsa_decrypt` 的 `UnicodeDecodeError` 分支被前置的 `ValueError` 吞掉,
88
+ 现按子类优先捕获并给出准确的错误说明
89
+ - `is_url` 接受未编码反斜杠(浏览器会将其归一为斜杠,存在主机混淆/校验绕过面),现拒绝
90
+ - 日志文件名安全校验覆盖 Windows 盘符相对路径(如 `D:evil`)、控制字符与保留设备名,
91
+ 避免绕过路径分隔符检查仍写出 `log_dir` 或在 emit 阶段静默失败
92
+ - `bcrypt_hash` 的 `rounds`、`rsa_generate_keys` 的 `bits` 非整数时泄漏原生 `TypeError`,
93
+ 现统一为 `ValidationError`
94
+ - `human_size`/`convert_size` 对超出浮点可表示范围的整数泄漏原生 `OverflowError`,
95
+ 现统一为 `ValidationError`
96
+ - Cron 字段与步长接受 `int()` 的宽松写法(下划线、正号、全角数字等),
97
+ 如 `1_0` 被静默解析为 10;现仅接受 ASCII 十进制数字,超长数字 token 统一为 `ParseError`
98
+ - `format_number` 与 `jsonx.loads`/`validate` 在超长整数触发 Python 位数上限时
99
+ 泄漏原生 `ValueError`,现分别统一为 `ValidationError` 与 `ParseError`;
100
+ `loads` 另拒绝 `1e400` 等超出 float 范围的指数值,不再解析为 `inf`
101
+ - `parse_user_agent` 补充 iOS 平台的 CriOS/FxiOS/OPiOS 浏览器标识识别
102
+ - `format_percent` 的有限浮点/超大指数 Decimal 输入乘以 100 后溢出(输出
103
+ "inf%"/"Infinity%")或抛出原生 `decimal.Overflow`,现统一抛 `ValidationError`;
104
+ `convert_size` 的有限浮点换算结果溢出为 inf 时同样显式失败
105
+ - `format_percent` 对经 Decimal 路径的超大数值(如 `1E+999995`,乘 100 未超 Decimal
106
+ 范围)增加输出位数上限(4300 位,与 `sys.get_int_max_str_digits` 默认值对齐),
107
+ 不再静默生成 KB~MB 级输出;`format_number` 的 `separator` 非字符串输入从原生
108
+ `TypeError` 收紧为 `ValidationError`(不分组请传空字符串)
109
+ - `imagex`/`pdfx` 图片读取对 Pillow 的解压炸弹异常(`DecompressionBombError`)
110
+ 统一转为 `ValidationError`
111
+ - 日志名称校验补充孤立代理项与 UTF-8/UTF-16 长度上限:避免配置成功后每次 emit
112
+ 因编码或文件系统长度限制静默丢日志
113
+ - `imagex` 保存阶段把编码器不支持当前图像模式的原生 `ValueError` 统一为
114
+ `ValidationError`(如 RGBA 保存为 EPS)
115
+ - Emoji“手势”与“自然”分类内的重复条目已去重(避免随机取值概率偏斜)
116
+
117
+ ### Added
118
+
119
+ - PyPI 发布完整指南(docs/publish.md):Trusted Publisher / twine / uv 三种方式、
120
+ TestPyPI 演练、发布后验证与常见问题排查
121
+
122
+ ### Changed
123
+
124
+ - 入门示例改用 POST 请求体提交密码,Django 上传示例处理缺失文件,并澄清异常与随机源约定
125
+ - `java_fields` 类型推断改按分词整词匹配(修正 message/image/paid/grid/validate 等误判;
126
+ 全小写复合词如 `userid` 不再推断为 Long,建议使用驼峰或下划线命名)
127
+ - `json_to_yaml` 智能类型转换与 `jsonx` 对称(datetime/set/Decimal/UUID/bytes 等含子类),
128
+ YAML 原生时间戳改输出 ISO 字符串
129
+ - `compress_image` 的 `quality` 按文档收紧为 1~95(此前越界值静默透传 Pillow)
130
+ - `mask` 校验 `mask_char` 须为单字符;`validate_xml` 非 str 输入返回 False
131
+ - `retry`/`rate_limit`/`human_duration` 等参数校验显式化(非法类型与非有限数值抛统一异常)
132
+ - README 时间 API 措辞修正(本地时间函数返回 naive datetime,aware 场景用 `now_utc`)
133
+ - `convert_size`/`human_size` 数值入参类型标注改为 `int | float`;日志 handler 构建逻辑
134
+ 按主/分类职责拆分,`get_logger` 保持单一入口
135
+ - Ruff 规则集扩展 `C4`/`PERF`/`PIE`(现有代码零违规)
136
+ - 修正文档中的 Emoji 数量描述(实际约 600 个)
137
+
138
+ ## [0.1.0] - 2026-11-07
139
+
140
+ ### Added
141
+
142
+ - 零依赖核心(纯标准库)23 个模块:encoding/hashing/times/text/jsonx/xmlix/diffx/formatx/webdata/chardata/bytesize/ids/password/validator/convert/collx/retryx/cronx/misc/decorators/files/env/log
143
+ - 可选依赖模块 7 个:security/jwtx/yamlix/imagex/qrcodex/barcodex/pdfx(按需 `pip install lantool[security]` 等启用)
144
+ - PEP 562 懒加载统一导出(`from lantool import xxx` 一行调用)
145
+ - `python -m lantool` 环境自检命令
146
+ - 日志工厂:总/级别/分类多文件、按天 + 100MB 双条件滚动、gzip 压缩、366 天保留
147
+ - PEP 561 类型标记(py.typed)、PEP 621 元数据、uv/pip 双兼容开发依赖
lantool-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LanTool Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
lantool-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.5
2
+ Name: lantool
3
+ Version: 0.1.0
4
+ Summary: 轻量实用的 Python 通用工具库:零依赖核心 + 按需扩展(编解码/哈希/加解密/时间/文本/日志等)
5
+ Project-URL: Homepage, https://gitee.com/lancelan6/lantool
6
+ Project-URL: Repository, https://gitee.com/lancelan6/lantool
7
+ Project-URL: Issues, https://gitee.com/lancelan6/lantool/issues
8
+ Project-URL: Changelog, https://gitee.com/lancelan6/lantool/blob/master/CHANGELOG.md
9
+ Author: LanTool Contributors
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: common,crypto,encoding,hashing,jwt,toolkit,utility,utils
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Utilities
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Provides-Extra: all
26
+ Requires-Dist: bcrypt>=4.2; extra == 'all'
27
+ Requires-Dist: cryptography>=43.0; extra == 'all'
28
+ Requires-Dist: pillow>=10.4; extra == 'all'
29
+ Requires-Dist: pyjwt>=2.9; extra == 'all'
30
+ Requires-Dist: pypdf>=4.3; extra == 'all'
31
+ Requires-Dist: python-barcode>=0.15; extra == 'all'
32
+ Requires-Dist: pyyaml>=6.0.2; extra == 'all'
33
+ Requires-Dist: qrcode>=7.4; extra == 'all'
34
+ Provides-Extra: barcode
35
+ Requires-Dist: pillow>=10.4; extra == 'barcode'
36
+ Requires-Dist: python-barcode>=0.15; extra == 'barcode'
37
+ Provides-Extra: dev
38
+ Requires-Dist: build>=1.2; extra == 'dev'
39
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
40
+ Requires-Dist: pytest>=8.0; extra == 'dev'
41
+ Requires-Dist: ruff>=0.8; extra == 'dev'
42
+ Provides-Extra: image
43
+ Requires-Dist: pillow>=10.4; extra == 'image'
44
+ Provides-Extra: jwt
45
+ Requires-Dist: pyjwt>=2.9; extra == 'jwt'
46
+ Provides-Extra: pdf
47
+ Requires-Dist: pillow>=10.4; extra == 'pdf'
48
+ Requires-Dist: pypdf>=4.3; extra == 'pdf'
49
+ Provides-Extra: qr
50
+ Requires-Dist: pillow>=10.4; extra == 'qr'
51
+ Requires-Dist: qrcode>=7.4; extra == 'qr'
52
+ Provides-Extra: security
53
+ Requires-Dist: bcrypt>=4.2; extra == 'security'
54
+ Requires-Dist: cryptography>=43.0; extra == 'security'
55
+ Provides-Extra: yaml
56
+ Requires-Dist: pyyaml>=6.0.2; extra == 'yaml'
57
+ Description-Content-Type: text/markdown
58
+
59
+ # lantool
60
+
61
+ [![PyPI](https://img.shields.io/pypi/v/lantool.svg)](https://pypi.org/project/lantool/)
62
+ [![Python](https://img.shields.io/pypi/pyversions/lantool.svg)](https://pypi.org/project/lantool/)
63
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
64
+
65
+ 轻量实用的 Python 通用工具库:**零依赖核心 + 按需扩展**。
66
+
67
+ - **开箱即用**:`pip install lantool` 后 `from lantool import sha256, base64_encode` 一行调用,无需实例化、无需配置;
68
+ - **零依赖核心**:约七成功能(编解码/哈希/时间/文本/JSON/日志/校验/Cron 等 23 个模块)纯标准库实现,完全离线可用;
69
+ - **按需扩展**:加解密、JWT、图片、PDF 等通过 extras 按需安装,缺失时给出清晰的安装提示;
70
+ - **源码即拷即用**:整包 `src/lantool` 拷入任意工程(FastAPI / Flask / Django / 脚本)同样直接 `import lantool` 使用;
71
+ - **Python 3.11+**:时间 API 避开 3.12+ 废弃接口(如 `utcnow`),提供 timezone-aware 的 `now_utc`;PEP 561 类型标记,IDE 补全友好。
72
+
73
+ ## 安装
74
+
75
+ ```bash
76
+ # pip
77
+ pip install lantool # 零依赖核心
78
+ pip install "lantool[security]" # 加解密(AES/RSA/Bcrypt)
79
+ pip install "lantool[all]" # 全功能一键安装
80
+
81
+ # uv
82
+ uv pip install lantool
83
+ uv add "lantool[all]" # 在 uv 管理的项目中添加依赖
84
+ ```
85
+
86
+ ### 可选功能(extras)
87
+
88
+ | extras | 功能 | 依赖 |
89
+ | --- | --- | --- |
90
+ | (无) | 核心 23 模块(纯标准库) | 无 |
91
+ | `security` | AES/DES/3DES/RSA/Bcrypt | `cryptography`、`bcrypt` |
92
+ | `jwt` | JWT 签发与校验 | `PyJWT` |
93
+ | `yaml` | JSON/YAML 互转 | `PyYAML` |
94
+ | `image` | 图片压缩/水印/favicon | `Pillow` |
95
+ | `qr` | 二维码生成(PNG/SVG) | `qrcode`、`Pillow` |
96
+ | `barcode` | 条形码生成 | `python-barcode`、`Pillow` |
97
+ | `pdf` | PDF 拆分/合并/水印/图片转 PDF | `pypdf`、`Pillow` |
98
+ | `all` | 以上全部 | — |
99
+
100
+ 未安装对应依赖时调用可选功能,会得到明确提示:
101
+
102
+ ```
103
+ OptionalDependencyError: 缺少可选依赖 cryptography,请先安装: pip install "lantool[security]" 或 uv pip install "lantool[security]"
104
+ ```
105
+
106
+ ## 快速开始
107
+
108
+ ### 编解码与哈希
109
+
110
+ ```python
111
+ from lantool import base64_encode, base64_decode, sha256, url_encode, convert_base
112
+
113
+ base64_encode("你好 lantool") # '5L2g5aW9IGxhbnRvb2w='
114
+ base64_decode("5L2g5aW9IGxhbnRvb2w=") # '你好 lantool'
115
+ sha256("abc") # 'ba7816bf8f01cfea...'
116
+ url_encode("a b/c") # 'a%20b%2Fc'
117
+ convert_base("hello", 36, 10) # '29234652'(支持 2~36 任意进制)
118
+ ```
119
+
120
+ ### 时间与时间戳
121
+
122
+ ```python
123
+ from lantool import now_str, timestamp, from_timestamp, human_duration
124
+
125
+ now_str() # '2026-11-07 15:30:00'(默认格式 YYYY-MM-DD HH:MM:SS)
126
+ timestamp() # 1780000000(秒级)
127
+ timestamp(seconds=False) # 1780000000123(毫秒级)
128
+ from_timestamp(1700000000) # datetime(13 位毫秒自动识别)
129
+ human_duration(90061) # '1天1小时1分1秒'
130
+ ```
131
+
132
+ ### 文本与 JSON
133
+
134
+ ```python
135
+ from lantool import to_snake, to_camel, java_fields, pretty, compact, dumps
136
+ from datetime import datetime
137
+
138
+ to_snake("HTTPServer") # 'http_server'
139
+ to_camel("user_login_count") # 'userLoginCount'
140
+ java_fields("id\nuserName\nprice\ncreateTime\nisVip")
141
+ # private Long id;
142
+ # private String userName;
143
+ # private BigDecimal price;
144
+ # private LocalDateTime createTime;
145
+ # private Boolean isVip;
146
+
147
+ dumps({"at": datetime.now()}) # datetime 自动 ISO 序列化
148
+ compact('{"a": 1}') # '{"a":1}'
149
+ pretty({"list": [1, 2]}) # 格式化缩进,中文原样输出
150
+ ```
151
+
152
+ ### 加解密与 JWT(需 extras)
153
+
154
+ ```python
155
+ from lantool import aes_encrypt, aes_decrypt, jwt_encode, jwt_decode, bcrypt_hash, bcrypt_verify
156
+
157
+ token = aes_encrypt("机密数据", "your-key") # AES-256-GCM,默认推荐
158
+ aes_decrypt(token, "your-key") # '机密数据'
159
+
160
+ jwt = jwt_encode({"sub": "user-1"}, "32-byte-secret...!!", expires_in=3600)
161
+ jwt_decode(jwt, "32-byte-secret...!!") # {'sub': 'user-1', 'iat': ..., 'exp': ...}
162
+
163
+ hashed = bcrypt_hash("my-password") # 口令存储推荐
164
+ bcrypt_verify("my-password", hashed) # True
165
+ ```
166
+
167
+ ### 日志(总 + 级别 + 分类,双条件滚动)
168
+
169
+ ```python
170
+ from lantool import get_logger
171
+
172
+ log = get_logger("app") # logs/app.log(总)+ app_error.log + app_warning.log
173
+ access = get_logger("app.access") # 分类:logs/app_access.log,同时汇入总日志与控制台
174
+
175
+ log.info("服务启动")
176
+ access.info("GET /api/users 200")
177
+ log.error("数据库连接失败")
178
+ ```
179
+
180
+ 单文件超 100MB 或跨天自动滚动,旧日志 gzip 压缩,默认保留 366 天(全部可配置)。
181
+
182
+ ### 更多示例
183
+
184
+ - **[从零开始完整指南](docs/getting-started.md)** —— 安装部署、自检、快速上手、FastAPI/Flask/Django 集成实战、日志部署、故障排查
185
+ - **[使用指南](docs/usage.md)** —— 全部 API 说明与示例
186
+
187
+ 自检本机环境:
188
+
189
+ ```bash
190
+ python -m lantool # 输出版本、Python 环境与各 extras 可用性
191
+ ```
192
+
193
+ ## 功能矩阵
194
+
195
+ | 领域 | 模块 | 主要能力 |
196
+ | --- | --- | --- |
197
+ | 编解码 | `encoding` | Base64 / URL / Hex / Unicode 中文互转 / 摩斯密码 / 2~36 进制 / 图片转 Base64 |
198
+ | 哈希 | `hashing` | MD5 / SHA1 / SHA224-512 / HMAC / 文件哈希 / CRC32 |
199
+ | 时间 | `times` | 时间戳(秒/毫秒互转)/ 多格式当前时间 / 人性化时长 |
200
+ | 文本 | `text` | 驼峰互转 / 大小写 / 字数统计 / 自然排序 / 脱敏 / Java 字段生成 |
201
+ | 数据格式 | `jsonx` `xmlix` `diffx` | JSON 智能序列化与格式化 / XML 格式化 / 文本差异对比 |
202
+ | 数字格式 | `formatx` `bytesize` | 千分位 / 货币 / 百分比 / bit~EB 字节单位换算 |
203
+ | 校验 | `validator` | 邮箱 / 大陆手机号 / IPv4-6 / URL / 18 位身份证(含校验码) |
204
+ | 标识 | `ids` `password` | UUIDv1/3/4/5/**7** / 短 ID / NanoID / 随机密码与强度评估 |
205
+ | 容错 | `retryx` `decorators` | 重试(指数退避)/ 计时 / 抑制异常 / 单机限流 / 模块分隔块 |
206
+ | 定时 | `cronx` | Cron 解析 / 下次运行时间 / 中文描述 |
207
+ | 数据表 | `webdata` `chardata` | HTTP 状态码 / Content-Type / UA 列表与解析 / ASCII / HTML 实体 / Emoji 大全 |
208
+ | 文件 | `files` `env` | 安全读写(原子写)/ 文件信息 / MIME / 环境变量类型安全读取 |
209
+ | 日志 | `log` | 多文件日志工厂:总/级别/分类,双条件滚动 + 压缩 + 保留策略 |
210
+ | 加解密 | `security` `jwtx` | AES-GCM/CBC、DES/3DES、RSA、Bcrypt、JWT(可选依赖) |
211
+ | 媒体 | `imagex` `qrcodex` `barcodex` `pdfx` | 图片压缩/水印/favicon、二维码、条形码、PDF 处理(可选依赖) |
212
+ | 集合 | `collx` `convert` | 深度合并 / 分块 / 扁平化 / 去重 / 类型安全转换 |
213
+
214
+ ## FAQ
215
+
216
+ **Q: 为什么还有 MD5?** 兼容遗留系统与缓存键等非安全场景而保留;`md5()` 的文档与本文均标注其不适用于安全用途,本库一切默认算法均为 SHA256。
217
+
218
+ **Q: 能离线使用吗?** 能。核心零依赖;可选功能在安装好对应依赖后同样完全离线运行,不发起任何网络请求。
219
+
220
+ **Q: 会影响我的应用日志吗?** 不会。lantool 作为库自身不配置任何 logger、不触碰 root logger;`get_logger` 仅在你显式调用时才创建独立的日志体系(`propagate=False`,与应用日志隔离)。
221
+
222
+ **Q: `convert.to_int` 与 `bytesize.convert_size` 什么区别?** 前者是类型转换域(str→int 等宽松转换),后者是存储单位换算域(KB→MB 等),分属不同模块以保持单一职责。
223
+
224
+ **Q: 如何发布到 PyPI?** 详见 **[发布到 PyPI 完整指南](docs/publish.md)**(Trusted Publisher / twine / uv 三种方式、TestPyPI 演练、常见问题排查)。本仓库托管于 [Gitee](https://gitee.com/lancelan6/lantool)(Gitee 不支持 Trusted Publisher),可本地 `python -m build && twine upload dist/*` 直接发布,或镜像到 GitHub 后使用 CI 中预留的 Trusted Publisher 自动发布。
225
+
226
+ ## 路线图
227
+
228
+ 以下功能刻意未实现(保持轻量),如有需要欢迎提 issue:
229
+
230
+ - 联网类:汇率查询、HTTP 客户端封装(本库定位离线工具集)
231
+ - 重依赖类:OCR 文字识别、二维码/条形码解析、PDF 转图片渲染
232
+ - 分布式限流(需 Redis 等外部状态存储)
233
+
234
+ ## 开发
235
+
236
+ ```bash
237
+ # 推荐 uv(自动读取 [dependency-groups])
238
+ uv sync # 安装开发依赖
239
+ uv sync --all-extras # 含全部可选依赖
240
+ uv run pytest # 运行测试
241
+ uv run ruff check src tests && uv run ruff format --check src tests
242
+
243
+ # 亦可用 pip
244
+ pip install -e ".[dev]"
245
+ pip install -e ".[all]"
246
+ ```
247
+
248
+ 发布:打 `v*` 标签推送即可触发 CI 构建,并通过 Trusted Publisher 自动发布到 PyPI。
249
+
250
+ ## 许可证
251
+
252
+ [MIT](LICENSE)
@@ -0,0 +1,194 @@
1
+ # lantool
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/lantool.svg)](https://pypi.org/project/lantool/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/lantool.svg)](https://pypi.org/project/lantool/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ 轻量实用的 Python 通用工具库:**零依赖核心 + 按需扩展**。
8
+
9
+ - **开箱即用**:`pip install lantool` 后 `from lantool import sha256, base64_encode` 一行调用,无需实例化、无需配置;
10
+ - **零依赖核心**:约七成功能(编解码/哈希/时间/文本/JSON/日志/校验/Cron 等 23 个模块)纯标准库实现,完全离线可用;
11
+ - **按需扩展**:加解密、JWT、图片、PDF 等通过 extras 按需安装,缺失时给出清晰的安装提示;
12
+ - **源码即拷即用**:整包 `src/lantool` 拷入任意工程(FastAPI / Flask / Django / 脚本)同样直接 `import lantool` 使用;
13
+ - **Python 3.11+**:时间 API 避开 3.12+ 废弃接口(如 `utcnow`),提供 timezone-aware 的 `now_utc`;PEP 561 类型标记,IDE 补全友好。
14
+
15
+ ## 安装
16
+
17
+ ```bash
18
+ # pip
19
+ pip install lantool # 零依赖核心
20
+ pip install "lantool[security]" # 加解密(AES/RSA/Bcrypt)
21
+ pip install "lantool[all]" # 全功能一键安装
22
+
23
+ # uv
24
+ uv pip install lantool
25
+ uv add "lantool[all]" # 在 uv 管理的项目中添加依赖
26
+ ```
27
+
28
+ ### 可选功能(extras)
29
+
30
+ | extras | 功能 | 依赖 |
31
+ | --- | --- | --- |
32
+ | (无) | 核心 23 模块(纯标准库) | 无 |
33
+ | `security` | AES/DES/3DES/RSA/Bcrypt | `cryptography`、`bcrypt` |
34
+ | `jwt` | JWT 签发与校验 | `PyJWT` |
35
+ | `yaml` | JSON/YAML 互转 | `PyYAML` |
36
+ | `image` | 图片压缩/水印/favicon | `Pillow` |
37
+ | `qr` | 二维码生成(PNG/SVG) | `qrcode`、`Pillow` |
38
+ | `barcode` | 条形码生成 | `python-barcode`、`Pillow` |
39
+ | `pdf` | PDF 拆分/合并/水印/图片转 PDF | `pypdf`、`Pillow` |
40
+ | `all` | 以上全部 | — |
41
+
42
+ 未安装对应依赖时调用可选功能,会得到明确提示:
43
+
44
+ ```
45
+ OptionalDependencyError: 缺少可选依赖 cryptography,请先安装: pip install "lantool[security]" 或 uv pip install "lantool[security]"
46
+ ```
47
+
48
+ ## 快速开始
49
+
50
+ ### 编解码与哈希
51
+
52
+ ```python
53
+ from lantool import base64_encode, base64_decode, sha256, url_encode, convert_base
54
+
55
+ base64_encode("你好 lantool") # '5L2g5aW9IGxhbnRvb2w='
56
+ base64_decode("5L2g5aW9IGxhbnRvb2w=") # '你好 lantool'
57
+ sha256("abc") # 'ba7816bf8f01cfea...'
58
+ url_encode("a b/c") # 'a%20b%2Fc'
59
+ convert_base("hello", 36, 10) # '29234652'(支持 2~36 任意进制)
60
+ ```
61
+
62
+ ### 时间与时间戳
63
+
64
+ ```python
65
+ from lantool import now_str, timestamp, from_timestamp, human_duration
66
+
67
+ now_str() # '2026-11-07 15:30:00'(默认格式 YYYY-MM-DD HH:MM:SS)
68
+ timestamp() # 1780000000(秒级)
69
+ timestamp(seconds=False) # 1780000000123(毫秒级)
70
+ from_timestamp(1700000000) # datetime(13 位毫秒自动识别)
71
+ human_duration(90061) # '1天1小时1分1秒'
72
+ ```
73
+
74
+ ### 文本与 JSON
75
+
76
+ ```python
77
+ from lantool import to_snake, to_camel, java_fields, pretty, compact, dumps
78
+ from datetime import datetime
79
+
80
+ to_snake("HTTPServer") # 'http_server'
81
+ to_camel("user_login_count") # 'userLoginCount'
82
+ java_fields("id\nuserName\nprice\ncreateTime\nisVip")
83
+ # private Long id;
84
+ # private String userName;
85
+ # private BigDecimal price;
86
+ # private LocalDateTime createTime;
87
+ # private Boolean isVip;
88
+
89
+ dumps({"at": datetime.now()}) # datetime 自动 ISO 序列化
90
+ compact('{"a": 1}') # '{"a":1}'
91
+ pretty({"list": [1, 2]}) # 格式化缩进,中文原样输出
92
+ ```
93
+
94
+ ### 加解密与 JWT(需 extras)
95
+
96
+ ```python
97
+ from lantool import aes_encrypt, aes_decrypt, jwt_encode, jwt_decode, bcrypt_hash, bcrypt_verify
98
+
99
+ token = aes_encrypt("机密数据", "your-key") # AES-256-GCM,默认推荐
100
+ aes_decrypt(token, "your-key") # '机密数据'
101
+
102
+ jwt = jwt_encode({"sub": "user-1"}, "32-byte-secret...!!", expires_in=3600)
103
+ jwt_decode(jwt, "32-byte-secret...!!") # {'sub': 'user-1', 'iat': ..., 'exp': ...}
104
+
105
+ hashed = bcrypt_hash("my-password") # 口令存储推荐
106
+ bcrypt_verify("my-password", hashed) # True
107
+ ```
108
+
109
+ ### 日志(总 + 级别 + 分类,双条件滚动)
110
+
111
+ ```python
112
+ from lantool import get_logger
113
+
114
+ log = get_logger("app") # logs/app.log(总)+ app_error.log + app_warning.log
115
+ access = get_logger("app.access") # 分类:logs/app_access.log,同时汇入总日志与控制台
116
+
117
+ log.info("服务启动")
118
+ access.info("GET /api/users 200")
119
+ log.error("数据库连接失败")
120
+ ```
121
+
122
+ 单文件超 100MB 或跨天自动滚动,旧日志 gzip 压缩,默认保留 366 天(全部可配置)。
123
+
124
+ ### 更多示例
125
+
126
+ - **[从零开始完整指南](docs/getting-started.md)** —— 安装部署、自检、快速上手、FastAPI/Flask/Django 集成实战、日志部署、故障排查
127
+ - **[使用指南](docs/usage.md)** —— 全部 API 说明与示例
128
+
129
+ 自检本机环境:
130
+
131
+ ```bash
132
+ python -m lantool # 输出版本、Python 环境与各 extras 可用性
133
+ ```
134
+
135
+ ## 功能矩阵
136
+
137
+ | 领域 | 模块 | 主要能力 |
138
+ | --- | --- | --- |
139
+ | 编解码 | `encoding` | Base64 / URL / Hex / Unicode 中文互转 / 摩斯密码 / 2~36 进制 / 图片转 Base64 |
140
+ | 哈希 | `hashing` | MD5 / SHA1 / SHA224-512 / HMAC / 文件哈希 / CRC32 |
141
+ | 时间 | `times` | 时间戳(秒/毫秒互转)/ 多格式当前时间 / 人性化时长 |
142
+ | 文本 | `text` | 驼峰互转 / 大小写 / 字数统计 / 自然排序 / 脱敏 / Java 字段生成 |
143
+ | 数据格式 | `jsonx` `xmlix` `diffx` | JSON 智能序列化与格式化 / XML 格式化 / 文本差异对比 |
144
+ | 数字格式 | `formatx` `bytesize` | 千分位 / 货币 / 百分比 / bit~EB 字节单位换算 |
145
+ | 校验 | `validator` | 邮箱 / 大陆手机号 / IPv4-6 / URL / 18 位身份证(含校验码) |
146
+ | 标识 | `ids` `password` | UUIDv1/3/4/5/**7** / 短 ID / NanoID / 随机密码与强度评估 |
147
+ | 容错 | `retryx` `decorators` | 重试(指数退避)/ 计时 / 抑制异常 / 单机限流 / 模块分隔块 |
148
+ | 定时 | `cronx` | Cron 解析 / 下次运行时间 / 中文描述 |
149
+ | 数据表 | `webdata` `chardata` | HTTP 状态码 / Content-Type / UA 列表与解析 / ASCII / HTML 实体 / Emoji 大全 |
150
+ | 文件 | `files` `env` | 安全读写(原子写)/ 文件信息 / MIME / 环境变量类型安全读取 |
151
+ | 日志 | `log` | 多文件日志工厂:总/级别/分类,双条件滚动 + 压缩 + 保留策略 |
152
+ | 加解密 | `security` `jwtx` | AES-GCM/CBC、DES/3DES、RSA、Bcrypt、JWT(可选依赖) |
153
+ | 媒体 | `imagex` `qrcodex` `barcodex` `pdfx` | 图片压缩/水印/favicon、二维码、条形码、PDF 处理(可选依赖) |
154
+ | 集合 | `collx` `convert` | 深度合并 / 分块 / 扁平化 / 去重 / 类型安全转换 |
155
+
156
+ ## FAQ
157
+
158
+ **Q: 为什么还有 MD5?** 兼容遗留系统与缓存键等非安全场景而保留;`md5()` 的文档与本文均标注其不适用于安全用途,本库一切默认算法均为 SHA256。
159
+
160
+ **Q: 能离线使用吗?** 能。核心零依赖;可选功能在安装好对应依赖后同样完全离线运行,不发起任何网络请求。
161
+
162
+ **Q: 会影响我的应用日志吗?** 不会。lantool 作为库自身不配置任何 logger、不触碰 root logger;`get_logger` 仅在你显式调用时才创建独立的日志体系(`propagate=False`,与应用日志隔离)。
163
+
164
+ **Q: `convert.to_int` 与 `bytesize.convert_size` 什么区别?** 前者是类型转换域(str→int 等宽松转换),后者是存储单位换算域(KB→MB 等),分属不同模块以保持单一职责。
165
+
166
+ **Q: 如何发布到 PyPI?** 详见 **[发布到 PyPI 完整指南](docs/publish.md)**(Trusted Publisher / twine / uv 三种方式、TestPyPI 演练、常见问题排查)。本仓库托管于 [Gitee](https://gitee.com/lancelan6/lantool)(Gitee 不支持 Trusted Publisher),可本地 `python -m build && twine upload dist/*` 直接发布,或镜像到 GitHub 后使用 CI 中预留的 Trusted Publisher 自动发布。
167
+
168
+ ## 路线图
169
+
170
+ 以下功能刻意未实现(保持轻量),如有需要欢迎提 issue:
171
+
172
+ - 联网类:汇率查询、HTTP 客户端封装(本库定位离线工具集)
173
+ - 重依赖类:OCR 文字识别、二维码/条形码解析、PDF 转图片渲染
174
+ - 分布式限流(需 Redis 等外部状态存储)
175
+
176
+ ## 开发
177
+
178
+ ```bash
179
+ # 推荐 uv(自动读取 [dependency-groups])
180
+ uv sync # 安装开发依赖
181
+ uv sync --all-extras # 含全部可选依赖
182
+ uv run pytest # 运行测试
183
+ uv run ruff check src tests && uv run ruff format --check src tests
184
+
185
+ # 亦可用 pip
186
+ pip install -e ".[dev]"
187
+ pip install -e ".[all]"
188
+ ```
189
+
190
+ 发布:打 `v*` 标签推送即可触发 CI 构建,并通过 Trusted Publisher 自动发布到 PyPI。
191
+
192
+ ## 许可证
193
+
194
+ [MIT](LICENSE)