tea-tool 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.
tea_tool-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Corenca
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.
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.3
2
+ Name: tea-tool
3
+ Version: 0.1.0
4
+ Summary: Commonly used Python development toolkits in business development.
5
+ Author: Corenca
6
+ Author-email: Corenca <corenca.wang@gmail.com>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2026 Corenca
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+ Requires-Dist: polars[pyarrow]>=1.44.1
29
+ Requires-Dist: pydantic>=2.13.5
30
+ Requires-Dist: fastexcel>=0.21.0 ; extra == 'excel'
31
+ Requires-Dist: xlsxwriter>=3.2.9 ; extra == 'excel'
32
+ Requires-Python: >=3.12
33
+ Provides-Extra: excel
34
+ Description-Content-Type: text/markdown
35
+
36
+ # tea-tool
37
+
38
+ Commonly used Python development toolkits in business development.
39
+
40
+ 业务开发常用的 Python 工具集,面向 Python >= 3.12,基于 polars 与 pydantic 构建,覆盖数据读写(CSV / Excel)、时间处理、数据脱敏、数据模型基类等高频场景。
41
+
42
+ ## 特性一览
43
+
44
+ | 模块 | 定位 | 状态 |
45
+ | --- | --- | --- |
46
+ | `tea_tool.util.collection` | 列表 / range / 任意可迭代对象的切分(按大小或按份数) | 已实现 |
47
+ | `tea_tool.util.csv` | CSV 与 polars DataFrame 互转 | 已实现 |
48
+ | `tea_tool.util.excel` | .xlsx 与 polars DataFrame 互转(需安装 `excel` 可选依赖) | 已实现 |
49
+ | `tea_tool.util.enum` | 带额外信息 `msg` 的值枚举基类 `ValueMsgEnum` | 已实现 |
50
+ | `tea_tool.datetime` | 时间处理:格式常量、时区常量、日历时刻边界与解析函数 | 已实现 |
51
+ | `tea_tool.masking` | 通用脱敏:机制(策略 / 规则 / 编排器)与内容(业务规则)分离 | 已实现 |
52
+ | `tea_tool.schema` | pydantic 模型统一基类与时间字段 JSON 序列化别名 | 已实现 |
53
+ | `tea_tool.django` / `tea_tool.storage` | Django / 对象存储相关工具 | 计划中 |
54
+
55
+ ## 安装
56
+
57
+ 要求 Python >= 3.12,已发布到 PyPI:
58
+
59
+ ```bash
60
+ # pip
61
+ pip install tea-tool
62
+ ```
63
+
64
+ ```bash
65
+ # uv
66
+ uv add tea-tool
67
+ ```
68
+
69
+ Excel 读写(`util.excel`)依赖可选的 fastexcel 与 xlsxwriter,按需安装:
70
+
71
+ ```bash
72
+ pip install 'tea-tool[excel]'
73
+ # 或
74
+ uv add 'tea-tool[excel]'
75
+ ```
76
+
77
+ 未安装可选依赖时,调用对应读写函数会抛出带安装指引的 ImportError,指引信息同时给出 pip 与 uv 两种安装方式。
78
+
79
+ ## 模块速览
80
+
81
+ 各模块的每个函数 / 类的参数说明与用法示例见对应源码 docstring。
82
+
83
+ - `tea_tool.util.collection` — 按固定大小切分可迭代对象(`chunked`、`chunk_list`),或按指定份数均分列表 / range(`split_list`、`split_range`),以及 range 版本的分块(`chunk_range`)。
84
+ - `tea_tool.util.csv` — `csv_to_df` 读取 CSV 为 polars DataFrame、`df_to_csv` 将 DataFrame 写出为 CSV。
85
+ - `tea_tool.util.excel` — `excel_to_df` 读取 .xlsx 为 polars DataFrame(支持文件表头到内存列名的映射)、`df_to_excel` 将 DataFrame 写出为 .xlsx。
86
+ - `tea_tool.util.enum` — `ValueMsgEnum`:成员以 `(value, msg)` 二元组声明,`value` 为枚举值,`msg` 携带对应额外信息,并提供按值查找的 `get()`。
87
+ - `tea_tool.datetime.formatter` — 常用日期时间格式常量:连字符 / 斜杠 / 中文 / ISO 等(如 `DATE_FORMAT`、`DATE_TIME_FORMAT_CN`)。
88
+ - `tea_tool.datetime.timezone` — 常用 IANA 时区常量(`UTC`、`SHANGHAI`、`NEW_YORK` 等)与获取本地时区的 `local_tz()`。
89
+ - `tea_tool.datetime.util` — 时段边界(`get_month_start` / `get_month_end` / `get_day_start` / `get_day_range`)、当月天数(`get_days_in_month`)、日期序列(`list_days`)、当前时刻(`get_local_time` / `get_utc_time`)、字符串解析(`parse_datetime`)。
90
+ - `tea_tool.masking` — 机制与内容分离的脱敏工具:策略定义"如何脱"(`KeepStrategy` / `ReplaceStrategy` / `HashStrategy` / `RemoveStrategy`),规则在自由文本中发现敏感片段,`Masker` 提供 `mask`(单值)、`mask_text`(自由文本自动识别)、`mask_dict`(结构化字段映射)三个入口;`presets` 模块提供中国大陆常见个人信息的预置识别规则(手机号、身份证、邮箱、IP、银行卡号)。
91
+ - `tea_tool.schema` — 项目数据模型统一基类 `BaseModel`(预设 `from_attributes`、`validate_assignment`、`populate_by_name`、忽略未声明字段等配置),以及 `DateTimeField` / `DateField` / `LocalDateTimeField` 时间字段标注(json 序列化时输出固定格式字符串)。
92
+
93
+ ## 开发与测试
94
+
95
+ 项目由 uv 管理,采用 src 布局,测试目录镜像源码目录结构:
96
+
97
+ ```bash
98
+ uv sync # 安装依赖(含 dev 组)
99
+ uv run pytest # 运行测试
100
+ uv run ruff check # 静态检查
101
+ uv run ruff format # 格式化
102
+ uv build # 构建 wheel / sdist
103
+ ```
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,72 @@
1
+ # tea-tool
2
+
3
+ Commonly used Python development toolkits in business development.
4
+
5
+ 业务开发常用的 Python 工具集,面向 Python >= 3.12,基于 polars 与 pydantic 构建,覆盖数据读写(CSV / Excel)、时间处理、数据脱敏、数据模型基类等高频场景。
6
+
7
+ ## 特性一览
8
+
9
+ | 模块 | 定位 | 状态 |
10
+ | --- | --- | --- |
11
+ | `tea_tool.util.collection` | 列表 / range / 任意可迭代对象的切分(按大小或按份数) | 已实现 |
12
+ | `tea_tool.util.csv` | CSV 与 polars DataFrame 互转 | 已实现 |
13
+ | `tea_tool.util.excel` | .xlsx 与 polars DataFrame 互转(需安装 `excel` 可选依赖) | 已实现 |
14
+ | `tea_tool.util.enum` | 带额外信息 `msg` 的值枚举基类 `ValueMsgEnum` | 已实现 |
15
+ | `tea_tool.datetime` | 时间处理:格式常量、时区常量、日历时刻边界与解析函数 | 已实现 |
16
+ | `tea_tool.masking` | 通用脱敏:机制(策略 / 规则 / 编排器)与内容(业务规则)分离 | 已实现 |
17
+ | `tea_tool.schema` | pydantic 模型统一基类与时间字段 JSON 序列化别名 | 已实现 |
18
+ | `tea_tool.django` / `tea_tool.storage` | Django / 对象存储相关工具 | 计划中 |
19
+
20
+ ## 安装
21
+
22
+ 要求 Python >= 3.12,已发布到 PyPI:
23
+
24
+ ```bash
25
+ # pip
26
+ pip install tea-tool
27
+ ```
28
+
29
+ ```bash
30
+ # uv
31
+ uv add tea-tool
32
+ ```
33
+
34
+ Excel 读写(`util.excel`)依赖可选的 fastexcel 与 xlsxwriter,按需安装:
35
+
36
+ ```bash
37
+ pip install 'tea-tool[excel]'
38
+ # 或
39
+ uv add 'tea-tool[excel]'
40
+ ```
41
+
42
+ 未安装可选依赖时,调用对应读写函数会抛出带安装指引的 ImportError,指引信息同时给出 pip 与 uv 两种安装方式。
43
+
44
+ ## 模块速览
45
+
46
+ 各模块的每个函数 / 类的参数说明与用法示例见对应源码 docstring。
47
+
48
+ - `tea_tool.util.collection` — 按固定大小切分可迭代对象(`chunked`、`chunk_list`),或按指定份数均分列表 / range(`split_list`、`split_range`),以及 range 版本的分块(`chunk_range`)。
49
+ - `tea_tool.util.csv` — `csv_to_df` 读取 CSV 为 polars DataFrame、`df_to_csv` 将 DataFrame 写出为 CSV。
50
+ - `tea_tool.util.excel` — `excel_to_df` 读取 .xlsx 为 polars DataFrame(支持文件表头到内存列名的映射)、`df_to_excel` 将 DataFrame 写出为 .xlsx。
51
+ - `tea_tool.util.enum` — `ValueMsgEnum`:成员以 `(value, msg)` 二元组声明,`value` 为枚举值,`msg` 携带对应额外信息,并提供按值查找的 `get()`。
52
+ - `tea_tool.datetime.formatter` — 常用日期时间格式常量:连字符 / 斜杠 / 中文 / ISO 等(如 `DATE_FORMAT`、`DATE_TIME_FORMAT_CN`)。
53
+ - `tea_tool.datetime.timezone` — 常用 IANA 时区常量(`UTC`、`SHANGHAI`、`NEW_YORK` 等)与获取本地时区的 `local_tz()`。
54
+ - `tea_tool.datetime.util` — 时段边界(`get_month_start` / `get_month_end` / `get_day_start` / `get_day_range`)、当月天数(`get_days_in_month`)、日期序列(`list_days`)、当前时刻(`get_local_time` / `get_utc_time`)、字符串解析(`parse_datetime`)。
55
+ - `tea_tool.masking` — 机制与内容分离的脱敏工具:策略定义"如何脱"(`KeepStrategy` / `ReplaceStrategy` / `HashStrategy` / `RemoveStrategy`),规则在自由文本中发现敏感片段,`Masker` 提供 `mask`(单值)、`mask_text`(自由文本自动识别)、`mask_dict`(结构化字段映射)三个入口;`presets` 模块提供中国大陆常见个人信息的预置识别规则(手机号、身份证、邮箱、IP、银行卡号)。
56
+ - `tea_tool.schema` — 项目数据模型统一基类 `BaseModel`(预设 `from_attributes`、`validate_assignment`、`populate_by_name`、忽略未声明字段等配置),以及 `DateTimeField` / `DateField` / `LocalDateTimeField` 时间字段标注(json 序列化时输出固定格式字符串)。
57
+
58
+ ## 开发与测试
59
+
60
+ 项目由 uv 管理,采用 src 布局,测试目录镜像源码目录结构:
61
+
62
+ ```bash
63
+ uv sync # 安装依赖(含 dev 组)
64
+ uv run pytest # 运行测试
65
+ uv run ruff check # 静态检查
66
+ uv run ruff format # 格式化
67
+ uv build # 构建 wheel / sdist
68
+ ```
69
+
70
+ ## License
71
+
72
+ MIT
@@ -0,0 +1,36 @@
1
+ [project]
2
+ name = "tea-tool"
3
+ version = "0.1.0"
4
+ readme = "README.md"
5
+ description = "Commonly used Python development toolkits in business development."
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "polars[pyarrow]>=1.44.1",
9
+ "pydantic>=2.13.5",
10
+ ]
11
+
12
+ [project.license]
13
+ file = "LICENSE"
14
+
15
+ [[project.authors]]
16
+ name = "Corenca"
17
+ email = "corenca.wang@gmail.com"
18
+
19
+ [project.optional-dependencies]
20
+ excel = [
21
+ "fastexcel>=0.21.0",
22
+ "xlsxwriter>=3.2.9",
23
+ ]
24
+
25
+ [build-system]
26
+ requires = ["uv_build>=0.12.8,<0.13.0"]
27
+ build-backend = "uv_build"
28
+
29
+ [dependency-groups]
30
+ dev = [
31
+ "fastexcel>=0.21.0",
32
+ "ipython>=9.17.1",
33
+ "pytest>=9.1.1",
34
+ "ruff>=0.16.5",
35
+ "xlsxwriter>=3.2.9",
36
+ ]
@@ -0,0 +1,33 @@
1
+ [project]
2
+ name = "tea-tool"
3
+ version = "0.1.0"
4
+ license = {file = "LICENSE"}
5
+ readme = "README.md"
6
+ description = "Commonly used Python development toolkits in business development."
7
+ authors = [
8
+ { name = "Corenca", email = "corenca.wang@gmail.com" }
9
+ ]
10
+ requires-python = ">=3.12"
11
+ dependencies = [
12
+ "polars[pyarrow]>=1.44.1",
13
+ "pydantic>=2.13.5",
14
+ ]
15
+
16
+ [project.optional-dependencies]
17
+ excel = [
18
+ "fastexcel>=0.21.0",
19
+ "xlsxwriter>=3.2.9",
20
+ ]
21
+
22
+ [build-system]
23
+ requires = ["uv_build>=0.12.8,<0.13.0"]
24
+ build-backend = "uv_build"
25
+
26
+ [dependency-groups]
27
+ dev = [
28
+ "fastexcel>=0.21.0",
29
+ "ipython>=9.17.1",
30
+ "pytest>=9.1.1",
31
+ "ruff>=0.16.5",
32
+ "xlsxwriter>=3.2.9",
33
+ ]
File without changes
File without changes
@@ -0,0 +1,40 @@
1
+ """日期时间 strftime/strptime 格式化模板常量。
2
+
3
+ 常量按粒度组织:DATE(日)、TIME(时间)、DATE_TIME(日期时间)、MONTH(月)与
4
+ YEAR 系压缩串(%Y%m%d…,常用于文件名/键)。同一粒度提供连字符(默认)、斜杠
5
+ (_SLASH)、中文(_CN)分隔变体;后缀 _ZONE 携带 %z 时区偏移、_ISO 为 ISO 8601
6
+ 扩展 T 分隔。注意:%f 恒为 6 位微秒且 strftime 不支持截宽,故含 %f 的模板按
7
+ 微秒(MICROSECOND)命名;%z 输出形如 +0800 无冒号(近似 RFC 3339,非严格)。
8
+ """
9
+
10
+ # 日期
11
+ DATE_FORMAT = "%Y-%m-%d"
12
+ DATE_FORMAT_SLASH = "%Y/%m/%d"
13
+ DATE_FORMAT_CN = "%Y年%m月%d日"
14
+
15
+ # 时间
16
+ TIME_FORMAT = "%H:%M:%S"
17
+ TIME_FORMAT_MINUTE = "%H:%M"
18
+ TIME_FORMAT_SLASH = "%H/%M/%S"
19
+ TIME_FORMAT_CN = "%H时%M分%S秒"
20
+
21
+ # 日期时间
22
+ DATE_TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
23
+ DATE_TIME_FORMAT_SLASH = "%Y/%m/%d %H:%M:%S"
24
+ DATE_TIME_FORMAT_CN = "%Y年%m月%d日 %H时%M分%S秒"
25
+ DATE_TIME_MICROSECOND = "%Y-%m-%d %H:%M:%S.%f"
26
+ DATE_TIME_ZONE = "%Y-%m-%d %H:%M:%S%z"
27
+ DATE_TIME_ISO = "%Y-%m-%dT%H:%M:%S"
28
+ DATE_TIME_ISO_ZONE = "%Y-%m-%dT%H:%M:%S%z"
29
+
30
+ # 月
31
+ MONTH_FORMAT = "%Y-%m"
32
+
33
+ # 年份系压缩串(无分隔符,常用于文件名/键)
34
+ YEAR = "%Y"
35
+ YEAR_TO_MONTH = "%Y%m"
36
+ YEAR_TO_DAY = "%Y%m%d"
37
+ YEAR_TO_HOUR = "%Y%m%d%H"
38
+ YEAR_TO_MINUTE = "%Y%m%d%H%M"
39
+ YEAR_TO_SECOND = "%Y%m%d%H%M%S"
40
+ YEAR_TO_MICROSECOND = "%Y%m%d%H%M%S.%f"
@@ -0,0 +1,58 @@
1
+ """常用时区常量与本地时区获取。
2
+
3
+ 常量覆盖 UTC 及主流业务城市的 IANA 时区(UTC-12 ~ UTC+14 各主要时区带),
4
+ 命名统一全大写、多词下划线分隔,可直接作为 tzinfo 参数传入 datetime 相关
5
+ 构造与 tea_tool.datetime.util 各函数。依赖 zoneinfo(Python 3.9+ 内置),
6
+ 具体时区数据取自已安装的 tzdata。
7
+ """
8
+
9
+ from datetime import datetime, tzinfo
10
+ from zoneinfo import ZoneInfo
11
+
12
+ UTC = ZoneInfo("UTC")
13
+
14
+ # 亚洲
15
+ SHANGHAI = ZoneInfo("Asia/Shanghai")
16
+ SINGAPORE = ZoneInfo("Asia/Singapore")
17
+ TOKYO = ZoneInfo("Asia/Tokyo")
18
+ SEOUL = ZoneInfo("Asia/Seoul")
19
+ HONG_KONG = ZoneInfo("Asia/Hong_Kong")
20
+ BANGKOK = ZoneInfo("Asia/Bangkok")
21
+ DUBAI = ZoneInfo("Asia/Dubai")
22
+ KOLKATA = ZoneInfo("Asia/Kolkata")
23
+
24
+ # 欧洲
25
+ LONDON = ZoneInfo("Europe/London")
26
+ PARIS = ZoneInfo("Europe/Paris")
27
+ BERLIN = ZoneInfo("Europe/Berlin")
28
+ AMSTERDAM = ZoneInfo("Europe/Amsterdam")
29
+ MOSCOW = ZoneInfo("Europe/Moscow")
30
+
31
+ # 美洲
32
+ NEW_YORK = ZoneInfo("America/New_York")
33
+ LOS_ANGELES = ZoneInfo("America/Los_Angeles")
34
+ CHICAGO = ZoneInfo("America/Chicago")
35
+ TORONTO = ZoneInfo("America/Toronto")
36
+ SAO_PAULO = ZoneInfo("America/Sao_Paulo")
37
+
38
+ # 大洋洲
39
+ SYDNEY = ZoneInfo("Australia/Sydney")
40
+ AUCKLAND = ZoneInfo("Pacific/Auckland")
41
+
42
+ # 非洲
43
+ JOHANNESBURG = ZoneInfo("Africa/Johannesburg")
44
+
45
+
46
+ def local_tz() -> tzinfo:
47
+ """返回系统本地时区。
48
+
49
+ 本地时区取自运行环境(TZ 环境变量或系统设置),与 datetime.now().astimezone()
50
+ 的时区归属一致;系统时区可被识别为具体区域时返回 ZoneInfo,否则退化为固定
51
+ 偏移时区。
52
+
53
+ Returns:
54
+ 当前系统本地时区对应的 tzinfo 对象。
55
+ """
56
+ local = datetime.now().astimezone().tzinfo
57
+ assert local is not None
58
+ return local
@@ -0,0 +1,194 @@
1
+ """datetime 日期时间通用工具。
2
+
3
+ 提供日历运算(月份首末日、逐日序列)与时刻获取(日零点、当日时间范围、
4
+ 本地/UTC 当前时间、字符串解析)。日历运算中的月份首末日与逐日序列
5
+ (get_month_start、get_month_end、list_days)仅接受 date;get_days_in_month
6
+ 接受 date/datetime(仅用其年月)。时刻类函数(get_day_start、get_day_range、
7
+ get_local_time、get_utc_time、parse_datetime)产出 datetime:date 输入按该日
8
+ 提升,datetime 输入保留 naive/aware 属性。时区语义:本模块只做钟面解释
9
+ (attach),不做跨时区换算;"本地时区"指系统时区,可用 timezone.local_tz()
10
+ 获取。
11
+ """
12
+
13
+ from calendar import monthrange
14
+ from datetime import UTC, date, datetime, time, timedelta, tzinfo
15
+
16
+ from .timezone import local_tz
17
+
18
+
19
+ def _shift_year_month(value: date | datetime, months: int) -> tuple[int, int]:
20
+ """计算 value 所在月偏移 months 个月后的 (年, 月)。
21
+
22
+ months 为负时同样正确(divmod 对负值取整向负无穷),例如 2026-01 偏移 -1
23
+ 得到 (2025, 12)。
24
+
25
+ Args:
26
+ value: 基准日期或时间,取其所在年与月。
27
+ months: 月份偏移量。
28
+
29
+ Returns:
30
+ 偏移后的 (年, 月) 二元组。
31
+ """
32
+ total = value.year * 12 + (value.month - 1) + months
33
+ year, month_index = divmod(total, 12)
34
+ return year, month_index + 1
35
+
36
+
37
+ def get_month_start(value: date | datetime, months: int = 0) -> date:
38
+ """返回 value 所在月偏移 months 个月后的首日。
39
+
40
+ months 为正表示偏移到之后的月份、为负表示之前的月份,0(默认)即 value 所在
41
+ 当月。value 无论 date 还是 datetime 均统一返回 date(datetime 仅取其年与月,
42
+ 不带时分秒与时区),例如 2026-01-31 10:30 偏移 1 个月返回 2026-02-01。
43
+
44
+ Args:
45
+ value: 基准日期或时间,取其所在月。
46
+ months: 月份偏移量,正为后负为前,默认当月。
47
+
48
+ Returns:
49
+ 目标月首日(date)。
50
+ """
51
+ year, month = _shift_year_month(value, months)
52
+ return date(year, month, 1)
53
+
54
+
55
+ def get_month_end(value: date | datetime, months: int = 0) -> date:
56
+ """返回 value 所在月偏移 months 个月后的末日。
57
+
58
+ 月份偏移语义与 get_month_start 一致(正后负前,0 为当月);返回目标月的最后
59
+ 一天,跨月取末日不受 value 原日影响,例如 2026-01-31 偏移 1 个月返回
60
+ 2026-02-28。value 无论 date 还是 datetime 均统一返回 date(datetime 仅取其
61
+ 年与月,不带时分秒与时区)。
62
+
63
+ Args:
64
+ value: 基准日期或时间,取其所在月。
65
+ months: 月份偏移量,正为后负为前,默认当月。
66
+
67
+ Returns:
68
+ 目标月末日(date)。
69
+ """
70
+ year, month = _shift_year_month(value, months)
71
+ last = monthrange(year, month)[1]
72
+ return date(year, month, last)
73
+
74
+
75
+ def get_days_in_month(value: date | datetime) -> int:
76
+ """返回 value 所在月的天数。
77
+
78
+ Args:
79
+ value: 基准日期或时间,取其所在月。
80
+
81
+ Returns:
82
+ 所在月的天数(平年 2 月为 28、闰年为 29)。
83
+ """
84
+ return monthrange(value.year, value.month)[1]
85
+
86
+
87
+ def get_day_start(value: date | datetime) -> datetime:
88
+ """返回 value 所在日的零点时刻。
89
+
90
+ 时刻域函数:date 输入提升为当日 00:00 的 naive datetime;naive datetime 清零
91
+ 时分秒与微秒;aware datetime 清零时刻但保留其 tzinfo(DST 切换日零点通常无
92
+ 歧义,不做 fold 处理)。
93
+
94
+ Args:
95
+ value: 基准日期或时间,取其所在日。
96
+
97
+ Returns:
98
+ 所在日零点对应的 datetime(naive 或保留输入的 aware 属性)。
99
+ """
100
+ if isinstance(value, datetime):
101
+ return value.replace(hour=0, minute=0, second=0, microsecond=0)
102
+ return datetime.combine(value, time.min)
103
+
104
+
105
+ def get_day_range(
106
+ value: date | datetime, tz: tzinfo | None = None
107
+ ) -> tuple[datetime, datetime]:
108
+ """返回 value 所在日的时间范围 [当日零点, 次日零点),左闭右开。
109
+
110
+ 时刻域函数,返回值恒为 datetime 对。时区规则:
111
+ - tz 显式给出时,两端钟面时间 attach 该时区(覆盖 value 自带时区,不换算);
112
+ - tz 缺省且 value 为 aware datetime 时,沿用 value 的时区;
113
+ - 其余情形(date / naive datetime)两端为 naive。
114
+ DST 切换日该范围的实际时长可能非 24 小时,但两端恒为该时区钟面零点。
115
+
116
+ Args:
117
+ value: 基准日期或时间,取其所在日。
118
+ tz: 目标时区;缺省时沿用输入时区或保持 naive。
119
+
120
+ Returns:
121
+ (当日零点, 次日零点) 元组。
122
+ """
123
+ if isinstance(value, datetime):
124
+ day = value.date()
125
+ resolved = tz if tz is not None else value.tzinfo
126
+ else:
127
+ day = value
128
+ resolved = tz
129
+ return (
130
+ datetime.combine(day, time.min, tzinfo=resolved),
131
+ datetime.combine(day + timedelta(days=1), time.min, tzinfo=resolved),
132
+ )
133
+
134
+
135
+ def list_days(start: date, end: date) -> list[date]:
136
+ """返回 [start, end) 区间内逐日 date 序列,左闭右开不含 end。
137
+
138
+ start 等于或晚于 end 时返回空列表。
139
+
140
+ Args:
141
+ start: 起始日期(含)。
142
+ end: 结束日期(不含)。
143
+
144
+ Returns:
145
+ 逐日 date 序列;start >= end 时为空列表。
146
+ """
147
+ result: list[date] = []
148
+ cursor = start
149
+ while cursor < end:
150
+ result.append(cursor)
151
+ cursor += timedelta(days=1)
152
+ return result
153
+
154
+
155
+ def get_local_time() -> datetime:
156
+ """返回系统本地时区的当前时刻(aware)。
157
+
158
+ Returns:
159
+ 带系统本地时区的当前 datetime。
160
+ """
161
+ return datetime.now().astimezone()
162
+
163
+
164
+ def get_utc_time() -> datetime:
165
+ """返回 UTC 的当前时刻(aware)。
166
+
167
+ Returns:
168
+ 带 UTC 时区的当前 datetime。
169
+ """
170
+ return datetime.now(UTC)
171
+
172
+
173
+ def parse_datetime(text: str, fmt: str, tz: tzinfo | None = None) -> datetime:
174
+ """按格式化模板将时间字符串解析为 aware datetime。
175
+
176
+ 结果为钟面解释:模板不含 %z 指令(字符串无时区信息)时,将解析出的钟面
177
+ 时间 attach 到 tz(缺省为系统本地时区);模板含 %z 指令时解析结果自带偏移
178
+ 并直接返回,此时忽略 tz 参数。DST 歧义时刻按钟面解释,不做特殊折叠处理。
179
+
180
+ Args:
181
+ text: 待解析的时间字符串。
182
+ fmt: strptime 格式化模板,可复用 tea_tool.datetime.formatter 常量。
183
+ tz: attach 目标时区,缺省为系统本地时区;模板含 %z 时无效。
184
+
185
+ Returns:
186
+ 解析得到的 aware datetime。
187
+
188
+ Raises:
189
+ ValueError: 当 text 与 fmt 不匹配时(strptime 原生异常)。
190
+ """
191
+ parsed = datetime.strptime(text, fmt) # noqa: DTZ007 解析结果 naive 时后续按 tz 参数 attach 时区
192
+ if parsed.tzinfo is not None:
193
+ return parsed
194
+ return parsed.replace(tzinfo=tz if tz is not None else local_tz())
File without changes
@@ -0,0 +1,39 @@
1
+ """通用脱敏工具:机制与内容分离。
2
+
3
+ 本包提供脱敏机制——策略(strategies)、文本发现规则(rules)与编排器
4
+ (Masker),不内置任何"哪些信息敏感、脱成什么样"的业务默认。规则与
5
+ 格式由使用方显式定义,可选用 presets 模块的预置规则集。
6
+
7
+ 典型用法(业务侧全局定义一次后复用)::
8
+
9
+ from tea_tool.masking import Masker, KeepStrategy
10
+ from tea_tool.masking.presets import CN_PII_RULES
11
+
12
+ phone_mask = KeepStrategy(prefix=3, suffix=4)
13
+ masker = Masker(rules=CN_PII_RULES)
14
+
15
+ masker.mask("13812345678", phone_mask) # 138****5678
16
+ masker.mask_text("联系 13812345678") # 联系 ***********
17
+ masker.mask_dict(data, fields={"phone": phone_mask})
18
+ """
19
+
20
+ from .core import Masker
21
+ from .rules import MaskMatch, MaskRule
22
+ from .strategies import (
23
+ HashStrategy,
24
+ KeepStrategy,
25
+ MaskStrategy,
26
+ RemoveStrategy,
27
+ ReplaceStrategy,
28
+ )
29
+
30
+ __all__ = [
31
+ "HashStrategy",
32
+ "KeepStrategy",
33
+ "MaskMatch",
34
+ "MaskRule",
35
+ "MaskStrategy",
36
+ "Masker",
37
+ "RemoveStrategy",
38
+ "ReplaceStrategy",
39
+ ]