mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-14 21:52:56 +08:00
* ✨ feat(core): 更新群组信息、Markdown 样式与 Pydantic 兼容层 - 【group】添加更新所有群组信息指令,并同步群组控制台数据 - 【markdown】支持合并 Markdown 的 CSS 来源 - 【pydantic-compat】提供 model_validate 兼容函数 * ✨ feat(core): 增强定时任务与群组标签管理,重构调度核心 ✨ 新功能 * **标签 (tags)**: 引入群组标签服务。 * 支持静态标签和动态标签 (基于 Alconna 规则自动匹配群信息)。 * 支持黑名单模式及 `@all` 特殊标签。 * 提供 `tag_manage` 超级用户插件 (list, create, edit, delete 等)。 * 群成员变动时自动失效动态标签缓存。 * **调度 (scheduler)**: 增强定时任务。 * 重构 `ScheduledJob` 模型,支持 `TAG`, `ALL_GROUPS` 等多种目标类型。 * 新增任务别名 (`name`)、创建者、权限、来源等字段。 * 支持一次性任务 (`schedule_once`) 和 Alconna 命令行参数 (`--params-cli`)。 * 新增执行选项 (`jitter`, `spread`) 和并发策略 (`ALLOW`, `SKIP`, `QUEUE`)。 * 支持批量获取任务状态。 ♻️ 重构优化 * **调度器核心**: * 拆分 `service.py` 为 `manager.py` (API) 和 `types.py` (模型)。 * 合并 `adapter.py` / `job.py` 至 `engine.py` (统一调度引擎)。 * 引入 `targeting.py` 模块管理任务目标解析。 * **调度器插件 (scheduler_admin)**: * 迁移命令参数校验逻辑至 `ArparmaBehavior`。 * 引入 `dependencies.py` 和 `data_source.py` 解耦业务逻辑与依赖注入。 * 适配新的任务目标类型展示。 * 🐛 fix(tag): 修复黑名单标签解析逻辑并优化标签详情展示 * ✨ feat(scheduler): 为多目标定时任务添加固定间隔串行执行选项 * ✨ feat(schedulerAdmin): 允许定时任务删除、暂停、恢复命令支持多ID操作 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
135 lines
3.7 KiB
Python
135 lines
3.7 KiB
Python
"""
|
|
Pydantic V1 & V2 兼容层模块
|
|
|
|
为 Pydantic V1 与 V2 版本提供统一的便捷函数与类,
|
|
包括 model_dump, model_copy, model_json_schema, parse_as 等。
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
from pathlib import Path
|
|
from typing import Any, TypeVar, get_args, get_origin
|
|
|
|
from nonebot.compat import PYDANTIC_V2, model_dump
|
|
from pydantic import VERSION, BaseModel
|
|
import ujson as json
|
|
|
|
T = TypeVar("T", bound=BaseModel)
|
|
V = TypeVar("V")
|
|
|
|
|
|
__all__ = [
|
|
"PYDANTIC_V2",
|
|
"_dump_pydantic_obj",
|
|
"_is_pydantic_type",
|
|
"compat_computed_field",
|
|
"dump_json_safely",
|
|
"model_copy",
|
|
"model_dump",
|
|
"model_json_schema",
|
|
"model_validate",
|
|
"parse_as",
|
|
]
|
|
|
|
|
|
def model_copy(
|
|
model: T, *, update: dict[str, Any] | None = None, deep: bool = False
|
|
) -> T:
|
|
"""
|
|
Pydantic `model.copy()` (v1) 和 `model.model_copy()` (v2) 的兼容函数。
|
|
"""
|
|
if PYDANTIC_V2:
|
|
return model.model_copy(update=update, deep=deep)
|
|
else:
|
|
update_dict = update or {}
|
|
return model.copy(update=update_dict, deep=deep)
|
|
|
|
|
|
def model_validate(model_class: type[T], obj: Any) -> T:
|
|
"""
|
|
Pydantic `model_validate` (v2) 与 `parse_obj` (v1) 的兼容函数。
|
|
"""
|
|
if PYDANTIC_V2:
|
|
return model_class.model_validate(obj)
|
|
else:
|
|
return model_class.parse_obj(obj)
|
|
|
|
|
|
if PYDANTIC_V2:
|
|
from pydantic import computed_field as compat_computed_field
|
|
else:
|
|
compat_computed_field = property
|
|
|
|
|
|
def model_json_schema(model_class: type[BaseModel], **kwargs: Any) -> dict[str, Any]:
|
|
"""
|
|
Pydantic `Model.schema()` (v1) 和 `Model.model_json_schema()` (v2) 的兼容函数。
|
|
"""
|
|
if PYDANTIC_V2:
|
|
return model_class.model_json_schema(**kwargs)
|
|
else:
|
|
return model_class.schema(by_alias=kwargs.get("by_alias", True))
|
|
|
|
|
|
def _is_pydantic_type(t: Any) -> bool:
|
|
"""
|
|
递归检查一个类型注解是否与 Pydantic BaseModel 相关。
|
|
"""
|
|
if t is None:
|
|
return False
|
|
origin = get_origin(t)
|
|
if origin:
|
|
return any(_is_pydantic_type(arg) for arg in get_args(t))
|
|
return isinstance(t, type) and issubclass(t, BaseModel)
|
|
|
|
|
|
def _dump_pydantic_obj(obj: Any) -> Any:
|
|
"""
|
|
递归地将一个对象内部的 Pydantic BaseModel 实例转换为字典。
|
|
支持单个实例、实例列表、实例字典等情况。
|
|
"""
|
|
if isinstance(obj, BaseModel):
|
|
return model_dump(obj)
|
|
if isinstance(obj, list):
|
|
return [_dump_pydantic_obj(item) for item in obj]
|
|
if isinstance(obj, dict):
|
|
return {key: _dump_pydantic_obj(value) for key, value in obj.items()}
|
|
return obj
|
|
|
|
|
|
def parse_as(type_: type[V], obj: Any) -> V:
|
|
"""
|
|
一个兼容 Pydantic V1 的 parse_obj_as 和V2的TypeAdapter.validate_python 的辅助函数。
|
|
"""
|
|
if VERSION.startswith("1"):
|
|
from pydantic import parse_obj_as
|
|
|
|
return parse_obj_as(type_, obj)
|
|
else:
|
|
from pydantic import TypeAdapter # type: ignore
|
|
|
|
return TypeAdapter(type_).validate_python(obj)
|
|
|
|
|
|
def dump_json_safely(obj: Any, **kwargs) -> str:
|
|
"""
|
|
安全地将可能包含 Pydantic 特定类型 (如 Enum) 的对象序列化为 JSON 字符串。
|
|
"""
|
|
|
|
def default_serializer(o):
|
|
if isinstance(o, Enum):
|
|
return o.value
|
|
if isinstance(o, datetime):
|
|
return o.isoformat()
|
|
if isinstance(o, Path):
|
|
return str(o.as_posix())
|
|
if isinstance(o, set):
|
|
return list(o)
|
|
if isinstance(o, BaseModel):
|
|
return model_dump(o)
|
|
raise TypeError(
|
|
f"Object of type {o.__class__.__name__} is not JSON serializable"
|
|
)
|
|
|
|
return json.dumps(obj, default=default_serializer, **kwargs)
|