diff --git a/src/astrbot_sdk/decorators.py b/src/astrbot_sdk/decorators.py index 015090763..7caf12d11 100644 --- a/src/astrbot_sdk/decorators.py +++ b/src/astrbot_sdk/decorators.py @@ -183,6 +183,10 @@ def _replace_filter(meta: HandlerMeta, spec: FilterSpec) -> None: meta.filters.append(spec) +def _has_filter_kind(meta: HandlerMeta, kind: str) -> bool: + return any(getattr(item, "kind", None) == kind for item in meta.filters) + + def _set_platform_filter( meta: HandlerMeta, values: list[str], @@ -197,6 +201,8 @@ def _set_platform_filter( existing = meta.decorator_sources.get("platforms") if existing is not None and existing != source: raise ValueError("platforms(...) 不能与 on_message(platforms=...) 混用") + if existing is None and _has_filter_kind(meta, "platform"): + raise ValueError("platforms(...) 不能与已有平台过滤器混用") meta.decorator_sources["platforms"] = source _replace_filter(meta, PlatformFilterSpec(platforms=normalized)) @@ -219,6 +225,10 @@ def _set_message_type_filter( raise ValueError( "group_only()/private_only()/message_types(...) 不能与已有消息类型约束混用" ) + if existing is None and _has_filter_kind(meta, "message_type"): + raise ValueError( + "group_only()/private_only()/message_types(...) 不能与已有消息类型过滤器混用" + ) meta.decorator_sources["message_types"] = source _replace_filter(meta, MessageTypeFilterSpec(message_types=normalized)) diff --git a/tests/test_decorators_filter_guards.py b/tests/test_decorators_filter_guards.py new file mode 100644 index 000000000..08d3a8be3 --- /dev/null +++ b/tests/test_decorators_filter_guards.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +import pytest + +from astrbot_sdk.decorators import ( + append_filter_meta, + get_handler_meta, + message_types, + platforms, +) +from astrbot_sdk.protocol.descriptors import ( + MessageTypeFilterSpec, + PlatformFilterSpec, +) + + +def test_platforms_rejects_existing_manual_platform_filter() -> None: + def handler() -> None: + return None + + append_filter_meta( + handler, + specs=[PlatformFilterSpec(platforms=["qq"])], + ) + + meta = get_handler_meta(handler) + assert meta is not None + assert meta.decorator_sources == {} + + with pytest.raises(ValueError, match="已有平台过滤器"): + platforms("wechat")(handler) + + +def test_message_types_rejects_existing_manual_message_type_filter() -> None: + def handler() -> None: + return None + + append_filter_meta( + handler, + specs=[MessageTypeFilterSpec(message_types=["group"])], + ) + + meta = get_handler_meta(handler) + assert meta is not None + assert meta.decorator_sources == {} + + with pytest.raises(ValueError, match="已有消息类型过滤器"): + message_types("private")(handler)