Skip to content

Commit

Permalink
style: 调整验证错误的名称
Browse files Browse the repository at this point in the history
符合 Pydantic 2.0 的风格
  • Loading branch information
he0119 committed Feb 3, 2024
1 parent 3a4f72b commit d83f341
Show file tree
Hide file tree
Showing 10 changed files with 51 additions and 58 deletions.
24 changes: 12 additions & 12 deletions src/plugins/publish/templates/render_error.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,35 @@
第 {{ loc[1] + 1 }} 个标签颜色错误<dt>请确保标签颜色符合十六进制颜色码规则。</dt>
{%- 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 == "missing" %}
{{ loc|loc_to_name }}: 无法匹配到数据。<dt>请确保填写该项目。</dt>
{%- elif type == "model_type" %}
{{ loc|loc_to_name }}: 格式错误。<dt>请确保其为字典。</dt>
{%- 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 == "string_too_long" %}
{{ loc|loc_to_name }}: 字符过多。<dt>请确保其不超过 {{ error.ctx.max_length }} 个字符。</dt>
Expand Down
4 changes: 2 additions & 2 deletions src/utils/validation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def validate_info(
{
"loc": ("metadata",),
"msg": "无法获取到插件元数据。",
"type": "value_error.metadata",
"type": "metadata",
"ctx": {"plugin_test_result": plugin_test_result},
"input": None,
}
Expand All @@ -93,7 +93,7 @@ def validate_info(
{
"loc": ("plugin_test",),
"msg": "插件无法正常加载",
"type": "value_error.plugin_test",
"type": "plugin_test",
"ctx": {"output": plugin_test_output},
"input": None,
}
Expand Down
5 changes: 2 additions & 3 deletions src/utils/validation/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@
CUSTOM_MESSAGES = {
"model_type": "值不是合法的字典",
"list_type": "值不是合法的列表",
"type_error.set": "值不是合法的集合",
"type_error.none.not_allowed": "值不能为 None",
"value_error.json": "JSON 格式不合法",
"set_type": "值不是合法的集合",
"json_type": "JSON 格式不合法",
"missing": "字段不存在",
"color_error": "颜色格式不正确",
"string_too_long": "字符串长度不能超过 {max_length} 个字符",
Expand Down
24 changes: 10 additions & 14 deletions src/utils/validation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,17 @@ class PyPIMixin(BaseModel):
@classmethod
def module_name_validator(cls, v: str) -> str:
if not PYTHON_MODULE_NAME_REGEX.match(v):
raise PydanticCustomError("value_error.module_name", "包名不符合规范")
raise PydanticCustomError("module_name", "包名不符合规范")
return v

@field_validator("project_link", mode="before")
@classmethod
def project_link_validator(cls, v: str) -> str:
if not PYPI_PACKAGE_NAME_PATTERN.match(v):
raise PydanticCustomError(
"value_error.project_link.name", "PyPI 项目名不符合规范"
)
raise PydanticCustomError("project_link.name", "PyPI 项目名不符合规范")

if v and not check_pypi(v):
raise PydanticCustomError(
"value_error.project_link.not_found", "PyPI 项目名不存在"
)
raise PydanticCustomError("project_link.not_found", "PyPI 项目名不存在")
return v

@model_validator(mode="before")
Expand All @@ -95,7 +91,7 @@ def prevent_duplication(
)
):
raise PydanticCustomError(
"value_error.duplication",
"duplication",
"PyPI 项目名 {project_link} 加包名 {module_name} 的值与商店重复",
{"project_link": project_link, "module_name": module_name},
)
Expand Down Expand Up @@ -139,7 +135,7 @@ def homepage_validator(cls, v: str) -> str:
status_code, msg = check_url(v)
if status_code != 200:
raise PydanticCustomError(
"value_error.homepage",
"homepage",
"项目主页无法访问",
{"status_code": status_code, "msg": msg},
)
Expand All @@ -151,7 +147,7 @@ def tags_validator(cls, v: str) -> list[dict[str, str]]:
try:
tags: list[Any] | Any = json.loads(v)
except json.JSONDecodeError:
raise PydanticCustomError("value_error.json", "JSON 格式不合法")
raise PydanticCustomError("json_type", "JSON 格式不合法")
return tags

@classmethod
Expand All @@ -173,7 +169,7 @@ class PluginPublishInfo(PublishInfo, PyPIMixin):
@classmethod
def type_validator(cls, v: str) -> str:
if v not in PLUGIN_VALID_TYPE:
raise PydanticCustomError("value_error.plugin.type", "插件类型不符合规范")
raise PydanticCustomError("plugin.type", "插件类型不符合规范")
return v

@field_validator("supported_adapters", mode="before")
Expand All @@ -193,22 +189,22 @@ def supported_adapters_validator(
try:
v = json.loads(v)
except json.JSONDecodeError:
raise PydanticCustomError("value_error.json", "JSON 格式不合法")
raise PydanticCustomError("json_type", "JSON 格式不合法")

# 如果是支持所有适配器,值应该是 None,不需要检查
if v is None:
return None

if not isinstance(v, (list, set)):
raise PydanticCustomError("type_error.set", "值应该是一个集合")
raise PydanticCustomError("set_type", "值应该是一个集合")

supported_adapters = {resolve_adapter_name(x) for x in v}
store_adapters = get_adapters()

missing_adapters = supported_adapters - store_adapters
if missing_adapters:
raise PydanticCustomError(
"value_error.plugin.supported_adapters.missing",
"supported_adapters.missing",
"适配器 {missing_adapters_str} 不存在",
{
"missing_adapters": list(missing_adapters),
Expand Down
30 changes: 15 additions & 15 deletions tests/publish/render/test_render_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ async def test_render_error_bot(app: App):
{
"loc": ("homepage",),
"msg": "项目主页不可访问。",
"type": "value_error.homepage",
"type": "homepage",
"ctx": {"status_code": 404},
"input": "https://www.baidu.com",
},
Expand Down Expand Up @@ -73,13 +73,13 @@ async def test_render_error_adapter(app: App):
{
"loc": ("module_name",),
"msg": "包名不符合规范。",
"type": "value_error.module_name",
"type": "module_name",
"input": "module_name/",
},
{
"loc": ("project_link",),
"msg": "PyPI 项目名不存在。",
"type": "value_error.project_link.not_found",
"type": "project_link.not_found",
"input": "project_link_failed",
},
{
Expand All @@ -92,7 +92,7 @@ async def test_render_error_adapter(app: App):
{
"loc": ("homepage",),
"msg": "项目主页不可访问。",
"type": "value_error.homepage",
"type": "homepage",
"ctx": {"status_code": 404},
"input": "https://www.baidu.com",
},
Expand Down Expand Up @@ -145,7 +145,7 @@ async def test_render_error_plugin(app: App, mocker: MockFixture):
{
"loc": (),
"msg": "PyPI 项目名 project_link 加包名 module_name 的值与商店重复。",
"type": "value_error.duplication",
"type": "duplication",
"ctx": {"project_link": "project_link", "module_name": "module_name"},
"input": None,
},
Expand All @@ -159,7 +159,7 @@ async def test_render_error_plugin(app: App, mocker: MockFixture):
{
"loc": ("homepage",),
"msg": "项目主页不可访问。",
"type": "value_error.homepage",
"type": "homepage",
"ctx": {"status_code": 404},
"input": "https://www.baidu.com",
},
Expand Down Expand Up @@ -214,14 +214,14 @@ async def test_render_error_plugin_load_test(app: App):
{
"loc": ("metadata",),
"msg": "无法获取到插件元数据。",
"type": "value_error.metadata",
"type": "metadata",
"ctx": {"plugin_test_result": False},
"input": None,
},
{
"loc": ("plugin_test",),
"msg": "插件无法正常加载",
"type": "value_error.plugin_test",
"type": "plugin_test",
"ctx": {"output": "output"},
"input": None,
},
Expand Down Expand Up @@ -257,7 +257,7 @@ async def test_render_error_plugin_metadata(app: App, mocker: MockFixture):
{
"loc": ("metadata",),
"msg": "无法获取到插件元数据。",
"type": "value_error.metadata",
"type": "metadata",
"ctx": {"plugin_test_result": True},
"input": None,
},
Expand Down Expand Up @@ -306,7 +306,7 @@ async def test_render_error_tags_invalid(app: App, mocker: MockFixture):
{
"loc": ("tags",),
"msg": "Invalid JSON",
"type": "value_error.json",
"type": "json_type",
"input": "not json",
},
],
Expand Down Expand Up @@ -342,20 +342,20 @@ async def test_render_type_eroor(app: App, mocker: MockFixture):
{
"loc": ("type",),
"msg": "插件类型不符合规范。",
"type": "value_error.plugin.type",
"type": "plugin.type",
"input": "invalid",
},
{
"loc": ("supported_adapters",),
"msg": "适配器 missing 不存在。",
"type": "value_error.plugin.supported_adapters.missing",
"type": "supported_adapters.missing",
"ctx": {"missing_adapters": {"missing"}},
"input": ["missing", "~onebot.v11"],
},
{
"loc": ("supported_adapters",),
"msg": "value is not a valid set",
"type": "type_error.set",
"type": "set_type",
"input": '"test"',
},
],
Expand Down Expand Up @@ -427,14 +427,14 @@ async def test_render_http_error(app: App, mocker: MockFixture):
{
"loc": ("homepage",),
"msg": "项目主页不可访问。",
"type": "value_error.homepage",
"type": "homepage",
"ctx": {"status_code": 404},
"input": "https://www.baidu.com",
},
{
"loc": ("homepage",),
"msg": "项目主页无法访问。",
"type": "value_error.homepage",
"type": "homepage",
"ctx": {
"status_code": -1,
"msg": "Request URL is missing an 'http://' or 'https://' protocol.",
Expand Down
4 changes: 2 additions & 2 deletions tests/utils/store_test/test_validate_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ async def test_validate_plugin_failed(
{
"loc": ("plugin_test",),
"msg": "插件无法正常加载",
"type": "value_error.plugin_test",
"type": "plugin_test",
"ctx": {"output": ""},
"input": None,
}
Expand Down Expand Up @@ -547,7 +547,7 @@ async def test_validate_plugin_failed_with_previous(
{
"loc": ("plugin_test",),
"msg": "插件无法正常加载",
"type": "value_error.plugin_test",
"type": "plugin_test",
"ctx": {"output": ""},
"input": None,
}
Expand Down
2 changes: 1 addition & 1 deletion tests/utils/validation/test_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async def test_bot_info_validation_failed_json_error(mocked_api: MockRouter) ->
assert "tags" not in result["data"]
assert result["errors"]
assert result["errors"][0]["loc"] == ("tags",)
assert result["errors"][0]["type"] == "value_error.json"
assert result["errors"][0]["type"] == "json_type"
assert result["errors"][0]["input"] == "not a json"
assert result["errors"][0]["msg"] == "JSON 格式不合法"

Expand Down
6 changes: 3 additions & 3 deletions tests/utils/validation/test_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ async def test_pypi_project_name_invalid(mocked_api: MockRouter) -> None:
assert "project_link" not in result["data"]
assert result["errors"]
assert result["errors"][0]["loc"] == ("project_link",)
assert result["errors"][0]["type"] == "value_error.project_link.name"
assert result["errors"][0]["type"] == "project_link.name"

assert mocked_api["homepage"].called

Expand All @@ -32,7 +32,7 @@ async def test_module_name_invalid(mocked_api: MockRouter) -> None:
assert "module_name" not in result["data"]
assert result["errors"]
assert result["errors"][0]["loc"] == ("module_name",)
assert result["errors"][0]["type"] == "value_error.module_name"
assert result["errors"][0]["type"] == "module_name"

assert mocked_api["project_link"].called
assert mocked_api["homepage"].called
Expand Down Expand Up @@ -61,7 +61,7 @@ async def test_name_duplication(mocked_api: MockRouter) -> None:
assert not result["valid"]
assert result["errors"]
assert result["errors"][0]["loc"] == ()
assert result["errors"][0]["type"] == "value_error.duplication"
assert result["errors"][0]["type"] == "duplication"

assert not mocked_api["project_link1"].called
assert not mocked_api["homepage"].called
Expand Down
8 changes: 3 additions & 5 deletions tests/utils/validation/test_plugin_supported_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async def test_plugin_supported_adapters_set(mocked_api: MockRouter) -> None:
assert not result["valid"]
assert "supported_adapters" not in result["data"]
assert result["errors"]
assert result["errors"][0]["type"] == "type_error.set"
assert result["errors"][0]["type"] == "set_type"
assert result["errors"][0]["msg"] == "值不是合法的集合"

assert mocked_api["homepage"].called
Expand All @@ -46,7 +46,7 @@ async def test_plugin_supported_adapters_json(mocked_api: MockRouter) -> None:
assert not result["valid"]
assert "supported_adapters" not in result["data"]
assert result["errors"]
assert result["errors"][0]["type"] == "value_error.json"
assert result["errors"][0]["type"] == "json_type"
assert result["errors"][0]["msg"] == "JSON 格式不合法"

assert mocked_api["homepage"].called
Expand All @@ -68,9 +68,7 @@ async def test_plugin_supported_adapters_missing_adapters(
assert not result["valid"]
assert "supported_adapters" not in result["data"]
assert result["errors"]
assert (
result["errors"][0]["type"] == "value_error.plugin.supported_adapters.missing"
)
assert result["errors"][0]["type"] == "supported_adapters.missing"
assert result["errors"][0]["msg"] == "适配器 nonebot.adapters.qq 不存在"
assert "ctx" in result["errors"][0]
assert result["errors"][0]["ctx"]["missing_adapters"] == ["nonebot.adapters.qq"]
Expand Down
2 changes: 1 addition & 1 deletion tests/utils/validation/test_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ async def test_tags_json_invalid(mocked_api: MockRouter) -> None:
assert "tags" not in result["data"]
assert result["errors"]
assert result["errors"][0]["loc"] == ("tags",)
assert result["errors"][0]["type"] == "value_error.json"
assert result["errors"][0]["type"] == "json_type"

assert mocked_api["project_link"].called
assert mocked_api["homepage"].called
Expand Down

0 comments on commit d83f341

Please sign in to comment.