Skip to content

Commit

Permalink
feat: 升级至 Pydantic 2 (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
he0119 authored Feb 5, 2024
1 parent 6ea7456 commit 8fad612
Show file tree
Hide file tree
Showing 27 changed files with 1,484 additions and 1,147 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/lang/zh-CN/

## [Unreleased]

### Added

- 使用 Pydantic 2.0

## [3.2.4] - 2024-02-04

### Fixed
Expand Down
1,394 changes: 763 additions & 631 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ repository = "https://github.com/nonebot/noneflow"

[tool.poetry.dependencies]
python = "^3.10"
nonebot2 = { extras = ["httpx"], version = "^2.0.0" }
nonebot-adapter-github = "^0.3.0"
nonebot2 = { git = "https://github.com/nonebot/nonebot2.git" }
nonebot-adapter-github = { git = "https://github.com/nonebot/adapter-github.git" }
pre-commit = "^3.3.2"
jinja2 = "^3.1.2"
pydantic-extra-types = "^2.5.0"

[tool.poetry.group.plugin.dependencies]
click = "^8.1.3"
Expand Down
22 changes: 12 additions & 10 deletions src/plugins/publish/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ async def handle_pr_close(
async with bot.as_installation(installation_id):
issue = (
await bot.rest.issues.async_get(
**repo_info.dict(), issue_number=related_issue_number
**repo_info.model_dump(), issue_number=related_issue_number
)
).parsed_data
if issue.state == "open":
logger.info(f"正在关闭议题 #{related_issue_number}")
await bot.rest.issues.async_update(
**repo_info.dict(),
**repo_info.model_dump(),
issue_number=related_issue_number,
state="closed",
state_reason="completed"
Expand Down Expand Up @@ -129,9 +129,11 @@ async def check_rule(
event: IssuesOpened | IssuesReopened | IssuesEdited | IssueCommentCreated,
publish_type: PublishType | None = Depends(get_type_by_labels),
) -> bool:
if isinstance(
event, IssueCommentCreated
) and event.payload.comment.user.login.endswith(BOT_MARKER):
if (
isinstance(event, IssueCommentCreated)
and event.payload.comment.user
and event.payload.comment.user.login.endswith(BOT_MARKER)
):
logger.info("评论来自机器人,已跳过")
return False
if event.payload.issue.pull_request:
Expand Down Expand Up @@ -165,7 +167,7 @@ async def handle_publish_check(
# 所以需要获取最新的议题状态
issue = (
await bot.rest.issues.async_get(
**repo_info.dict(), issue_number=issue_number
**repo_info.model_dump(), issue_number=issue_number
)
).parsed_data

Expand Down Expand Up @@ -206,7 +208,7 @@ async def handle_publish_check(
# 如果之前已经创建了拉取请求,则将其转换为草稿
pulls = (
await bot.rest.pulls.async_list(
**repo_info.dict(), head=f"{repo_info.owner}:{branch_name}"
**repo_info.model_dump(), head=f"{repo_info.owner}:{branch_name}"
)
).parsed_data
if pulls and (pull := pulls[0]) and not pull.draft:
Expand All @@ -227,7 +229,7 @@ async def handle_publish_check(
# 不然会因为修改议题触发 Actions 导致标签没有正常打上
if issue.title != title:
await bot.rest.issues.async_update(
**repo_info.dict(), issue_number=issue_number, title=title
**repo_info.model_dump(), issue_number=issue_number, title=title
)
logger.info(f"议题标题已修改为 {title}")

Expand Down Expand Up @@ -266,7 +268,7 @@ async def handle_auto_merge(
async with bot.as_installation(installation_id):
pull_request = (
await bot.rest.pulls.async_get(
**repo_info.dict(), pull_number=event.payload.pull_request.number
**repo_info.model_dump(), pull_number=event.payload.pull_request.number
)
).parsed_data

Expand All @@ -275,7 +277,7 @@ async def handle_auto_merge(
await resolve_conflict_pull_requests([pull_request])

await bot.rest.pulls.async_merge(
**repo_info.dict(),
**repo_info.model_dump(),
pull_number=event.payload.pull_request.number,
merge_method="rebase",
)
Expand Down
17 changes: 11 additions & 6 deletions src/plugins/publish/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Any

from nonebot import get_driver
from pydantic import BaseModel, Extra, validator
from pydantic import BaseModel, ConfigDict, field_validator

from src.utils.plugin_test import strip_ansi

Expand All @@ -15,7 +15,9 @@ class PublishConfig(BaseModel):
registry_repository: str = "nonebot/registry"


class Config(BaseModel, extra=Extra.ignore):
class Config(BaseModel, extra="ignore"):
model_config = ConfigDict(coerce_numbers_to_str=True)

input_config: PublishConfig
github_repository: str
github_run_id: str
Expand All @@ -24,26 +26,29 @@ class Config(BaseModel, extra=Extra.ignore):
plugin_test_output: str = ""
plugin_test_metadata: dict[str, Any] | None = None

@validator("plugin_test_result", pre=True)
@field_validator("plugin_test_result", mode="before")
@classmethod
def plugin_test_result_validator(cls, v):
# 如果插件测试没有运行时,会得到一个空字符串
# 这里将其转换为布尔值,不然会报错
if v == "":
return False
return v

@validator("plugin_test_metadata", pre=True)
@field_validator("plugin_test_metadata", mode="before")
@classmethod
def plugin_test_metadata_validator(cls, v):
# 如果插件测试没有运行时,会得到一个空字符串
# 这里将其转换为 None,不然会报错
if v == "":
return None
return v

@validator("plugin_test_output", pre=True)
@field_validator("plugin_test_output", mode="before")
@classmethod
def plugin_test_output_validator(cls, v):
"""移除 ANSI 转义字符"""
return strip_ansi(v)


plugin_config = Config.parse_obj(get_driver().config)
plugin_config = Config.model_validate(dict(get_driver().config))
24 changes: 18 additions & 6 deletions src/plugins/publish/depends.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from githubkit.rest.models import IssuePropLabelsItemsOneof1, Label, PullRequestSimple
from githubkit.webhooks.models import Label as WebhookLabel
from githubkit.rest import (
IssuePropLabelsItemsOneof1,
Label,
PullRequestPropLabelsItems,
PullRequestSimple,
WebhookIssueCommentCreatedPropIssueAllof0PropLabelsItems,
WebhookIssuesOpenedPropIssuePropLabelsItems,
WebhookPullRequestReviewSubmittedPropPullRequestPropLabelsItems,
)
from nonebot.adapters.github import (
Bot,
GitHubBot,
Expand Down Expand Up @@ -56,8 +63,13 @@ def get_issue_title(

def get_type_by_labels(
labels: list[Label]
| list[WebhookLabel]
| list[str | IssuePropLabelsItemsOneof1] = Depends(get_labels),
| list[str | IssuePropLabelsItemsOneof1]
| list[PullRequestPropLabelsItems]
| list[WebhookIssuesOpenedPropIssuePropLabelsItems]
| list[WebhookIssueCommentCreatedPropIssueAllof0PropLabelsItems]
| list[WebhookPullRequestReviewSubmittedPropPullRequestPropLabelsItems] = Depends(
get_labels
),
) -> PublishType | None:
"""通过标签获取类型"""
return utils.get_type_by_labels(labels)
Expand All @@ -74,7 +86,7 @@ async def get_pull_requests_by_label(
publish_type: PublishType = Depends(get_type_by_labels),
) -> list[PullRequestSimple]:
pulls = (
await bot.rest.pulls.async_list(**repo_info.dict(), state="open")
await bot.rest.pulls.async_list(**repo_info.model_dump(), state="open")
).parsed_data
return [
pull
Expand All @@ -96,7 +108,7 @@ async def get_installation_id(
) -> int:
"""获取 GitHub App 的 Installation ID"""
installation = (
await bot.rest.apps.async_get_repo_installation(**repo_info.dict())
await bot.rest.apps.async_get_repo_installation(**repo_info.model_dump())
).parsed_data
return installation.id

Expand Down
42 changes: 21 additions & 21 deletions src/plugins/publish/templates/render_error.md.jinja
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
{% macro render_error(error) %}
{% set loc = error.loc %}
{% set type = error.type %}
{%- if loc|length == 3 and loc[0] == "tags" and type == "value_error.missing" %}
{%- if loc|length == 3 and loc[0] == "tags" and type == "missing" %}
第 {{ loc[1] + 1 }} 个标签缺少 {{ loc[2] }} 字段。<dt>请确保标签字段完整。</dt>
{% elif loc|length == 3 and loc[0] == "tags" and type == "value_error.any_str.max_length" %}
{% elif loc|length == 3 and loc[0] == "tags" and type == "string_too_long" %}
第 {{ loc[1] + 1 }} 个标签名称过长<dt>请确保标签名称不超过 10 个字符。</dt>
{%- elif loc|length == 3 and loc[0] == "tags" and type == "value_error.color" %}
{%- elif loc|length == 3 and loc[0] == "tags" and type == "color_error" %}
第 {{ loc[1] + 1 }} 个标签颜色错误<dt>请确保标签颜色符合十六进制颜色码规则。</dt>
{%- elif loc|length == 2 and loc[0] == "tags" and type == "type_error.dict" %}
{%- elif loc|length == 2 and loc[0] == "tags" and type == "model_type" %}
第 {{ loc[1] + 1 }} 个标签格式错误。<dt>请确保标签为字典。</dt>
{%- elif type == "value_error.homepage" and error.ctx.status_code != -1 %}
{%- elif type == "homepage" and error.ctx.status_code != -1 %}
项目 <a href="{{ error.input }}">主页</a> 返回状态码 {{ error.ctx.status_code }}。<dt>请确保你的项目主页可访问。</dt>
{%- elif type == "value_error.homepage" and error.ctx.status_code == -1 %}
{%- elif type == "homepage" and error.ctx.status_code == -1 %}
项目 <a href="{{ error.input }}">主页</a> 访问出错。<details><summary>错误信息</summary>{{ error.ctx.msg }}</details>
{%- elif type == "value_error.project_link.not_found" %}
{%- elif type == "project_link.not_found" %}
项目 <a href="https://pypi.org/project/{{ error.input }}/">{{ error.input }}</a> 未发布至 PyPI。<dt>请将你的项目发布至 PyPI。</dt>
{%- elif type == "value_error.project_link.name" %}
{%- elif type == "project_link.name" %}
PyPI 项目名 {{ error.input }} 不符合规范。<dt>请确保项目名正确。</dt>
{%- elif type == "value_error.module_name" %}
{%- elif type == "module_name" %}
包名 {{ error.input }} 不符合规范。<dt>请确保包名正确。</dt>
{%- elif type == "value_error.duplication" %}
{%- elif type == "duplication" %}
{{ error.msg }}<dt>请确保没有重复发布。</dt>
{%- elif type == "value_error.plugin_test" %}
{%- elif type == "plugin_test" %}
插件加载测试未通过。<details><summary>测试输出</summary>{{ error.ctx.output }}</details>
{%- elif type == "value_error.metadata" %}
{%- elif type == "metadata" %}
无法获取到插件元数据。<dt>{{ "请填写插件元数据" if error.ctx.plugin_test_result else "请确保插件正常加载" }}。</dt>
{%- elif type == "value_error.plugin.type" %}
{%- elif type == "plugin.type" %}
插件类型 {{ error.input }} 不符合规范。<dt>请确保插件类型正确,当前仅支持 application 与 library。</dt>
{%- elif type == "value_error.plugin.supported_adapters.missing" %}
{%- elif type == "supported_adapters.missing" %}
适配器 {{ ', '.join(error.ctx.missing_adapters) }} 不存在。<dt>请确保适配器模块名称正确。</dt>
{%- elif type == "value_error.missing" %}
{%- elif type == "missing" %}
{{ loc|loc_to_name }}: 无法匹配到数据。<dt>请确保填写该项目。</dt>
{%- elif type == "type_error.dict" %}
{%- elif type == "model_type" %}
{{ loc|loc_to_name }}: 格式错误。<dt>请确保其为字典。</dt>
{%- elif type == "type_error.list" %}
{%- elif type == "list_type" %}
{{ loc|loc_to_name }}: 格式错误。<dt>请确保其为列表。</dt>
{%- elif type == "type_error.set" %}
{%- elif type == "set_type" %}
{{ loc|loc_to_name }}: 格式错误。<dt>请确保其为集合。</dt>
{%- elif type == "value_error.json" %}
{%- elif type == "json_type" %}
{{ loc|loc_to_name }}: 解码失败。<dt>请确保其为 JSON 格式。</dt>
{%- elif type == "value_error.any_str.max_length" %}
{{ loc|loc_to_name }}: 字符过多。<dt>请确保其不超过 {{ error.ctx.limit_value }} 个字符。</dt>
{%- elif type == "string_too_long" %}
{{ loc|loc_to_name }}: 字符过多。<dt>请确保其不超过 {{ error.ctx.max_length }} 个字符。</dt>
{%- else %}
{{ error.loc|loc_to_name }}: {{ error.msg }}
{%- endif %}
Expand Down
Loading

0 comments on commit 8fad612

Please sign in to comment.