From 56274c8ee63c5961f52b70c3b340613a58b75591 Mon Sep 17 00:00:00 2001 From: letr Date: Fri, 13 Mar 2026 16:28:04 +0800 Subject: [PATCH 1/3] docs: clarify compat package boundaries --- pyproject.toml | 2 +- src-new/astrbot_sdk/__init__.py | 8 ++++++-- src-new/astrbot_sdk/_legacy_api.py | 1 - src-new/astrbot_sdk/api/__init__.py | 7 ++++--- src-new/astrbot_sdk/compat.py | 8 +++++++- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 146cd1dd9..91c205060 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "astrbot-sdk" version = "0.1.0" -description = "Add your description here" +description = "AstrBot SDK with v4 runtime and legacy compatibility surfaces" readme = "README.md" requires-python = ">=3.12" dependencies = [ diff --git a/src-new/astrbot_sdk/__init__.py b/src-new/astrbot_sdk/__init__.py index ca314af9c..f0befb161 100644 --- a/src-new/astrbot_sdk/__init__.py +++ b/src-new/astrbot_sdk/__init__.py @@ -1,8 +1,12 @@ """AstrBot SDK 的顶层公共 API。 这里仅重新导出 v4 推荐直接导入的稳定入口。 -旧版兼容能力由 ``astrbot_sdk.api`` 与 ``astrbot_sdk.compat`` 承接, -避免把迁移层和原生 API 混在同一个包入口里。 + +- ``astrbot_sdk``: v4 原生稳定 API +- ``astrbot_sdk.compat``: 旧版顶层导入路径兼容入口 +- ``astrbot_sdk.api``: 历史 ``api.*`` 导入路径兼容面 + +这样可以把原生 API 与迁移入口明确分开,避免旧路径继续反向污染顶层包。 """ from .context import Context diff --git a/src-new/astrbot_sdk/_legacy_api.py b/src-new/astrbot_sdk/_legacy_api.py index b1bf66f07..f393f4789 100644 --- a/src-new/astrbot_sdk/_legacy_api.py +++ b/src-new/astrbot_sdk/_legacy_api.py @@ -19,7 +19,6 @@ from .clients.llm import LLMResponse from .context import Context as NewContext from .star import Star -# TODO-迁移文档要写,我好烦烦烦你烦烦烦你 MIGRATION_DOC_URL = "https://docs.astrbot.app/migration/v3" COMPAT_CONVERSATIONS_KEY = "__compat_conversations__" _warned_methods: set[str] = set() diff --git a/src-new/astrbot_sdk/api/__init__.py b/src-new/astrbot_sdk/api/__init__.py index 20b7882c1..b8273a1ab 100644 --- a/src-new/astrbot_sdk/api/__init__.py +++ b/src-new/astrbot_sdk/api/__init__.py @@ -1,4 +1,4 @@ -"""**兼容层** - 旧版 ``astrbot_sdk.api`` 导入路径的向后兼容入口。 +"""旧版 ``astrbot_sdk.api`` 导入路径的向后兼容入口。 .. warning:: 本目录是 ** 旧版本兼容层**,仅供旧版插件使用。 @@ -26,8 +26,9 @@ from astrbot_sdk.context import Context 设计说明: -- 兼容层通过 thin re-export 方式暴露旧版 API -- 不复制独立运行时逻辑,保持架构清晰 +- ``astrbot_sdk.api`` 是历史导入路径兼容面,不是 v4 原生 API 的推荐入口 +- 这里既包含薄重导出,也包含少量仍需保留行为的 compat 模块 +- 新增运行时逻辑应优先放在 v4 主路径,由 compat 层按需转发或包装 """ from loguru import logger diff --git a/src-new/astrbot_sdk/compat.py b/src-new/astrbot_sdk/compat.py index c7b545657..a1c1dd995 100644 --- a/src-new/astrbot_sdk/compat.py +++ b/src-new/astrbot_sdk/compat.py @@ -1,4 +1,10 @@ -"""旧版顶层导入路径的兼容重导出。""" +"""旧版顶层导入路径的兼容入口。 + +这个模块只承接历史上的顶层 legacy 导入习惯,例如 ``Context`` / +``CommandComponent``。更细的旧路径兼容仍保留在 ``astrbot_sdk.api`` 下。 + +新代码不应从这里导入;这里的职责是给旧插件一个明确、可隔离的旁路入口。 +""" from ._legacy_api import ( CommandComponent, From 6278bd112afe0b05782e0eaf2f185a8470f33849 Mon Sep 17 00:00:00 2001 From: letr Date: Fri, 13 Mar 2026 16:32:50 +0800 Subject: [PATCH 2/3] test: align runtime fixtures with maintained samples --- tests_v4/README.md | 3 +- tests_v4/helpers.py | 14 ++++ tests_v4/pytest.ini | 14 ---- tests_v4/test_entrypoints.py | 28 ++++++++ tests_v4/test_runtime.py | 27 ++++---- tests_v4/test_supervisor_migration.py | 98 +++++++++------------------ 6 files changed, 89 insertions(+), 95 deletions(-) delete mode 100644 tests_v4/pytest.ini diff --git a/tests_v4/README.md b/tests_v4/README.md index baf86e5f3..685941d6c 100644 --- a/tests_v4/README.md +++ b/tests_v4/README.md @@ -8,8 +8,7 @@ This test suite uses **pytest** with `pytest-asyncio` for testing the AstrBot SD ``` tests_v4/ -├── conftest.py # Shared fixtures and configuration -├── pytest.ini # Pytest configuration +├── conftest.py # Shared fixtures and path bootstrap ├── test_api_contract.py # API contract tests ├── test_api_decorators.py # Decorator and Star class tests ├── test_context.py # Context and CancelToken tests diff --git a/tests_v4/helpers.py b/tests_v4/helpers.py index ceef9e52d..57a40cfef 100644 --- a/tests_v4/helpers.py +++ b/tests_v4/helpers.py @@ -1,6 +1,7 @@ from __future__ import annotations # 启用延迟类型注解求值,避免循环引用 import asyncio +import shutil from types import SimpleNamespace from pathlib import Path @@ -106,3 +107,16 @@ async def drain_loop() -> None: 睡眠时间(0.05秒)足够短不会明显减慢测试,又足够长让事件循环有机会处理任务。 """ await asyncio.sleep(0.05) # 暂停当前协程50毫秒,让出控制权给事件循环 + + +def sample_plugin_dir(name: str) -> Path: + return Path(__file__).resolve().parents[1] / "test_plugin" / name + + +def copy_sample_plugin(name: str, destination: Path) -> Path: + shutil.copytree( + sample_plugin_dir(name), + destination, + ignore=shutil.ignore_patterns("__pycache__", "*.pyc"), + ) + return destination diff --git a/tests_v4/pytest.ini b/tests_v4/pytest.ini deleted file mode 100644 index db005f73a..000000000 --- a/tests_v4/pytest.ini +++ /dev/null @@ -1,14 +0,0 @@ -[pytest] -testpaths = . -python_files = test_*.py -python_classes = Test* -python_functions = test_* -asyncio_mode = auto -asyncio_default_fixture_loop_scope = function -filterwarnings = - ignore::DeprecationWarning - ignore::PendingDeprecationWarning -markers = - slow: marks tests as slow (deselect with '-m "not slow"') - integration: marks tests as integration tests - unit: marks tests as unit tests diff --git a/tests_v4/test_entrypoints.py b/tests_v4/test_entrypoints.py index 76d529f81..c06a7193b 100644 --- a/tests_v4/test_entrypoints.py +++ b/tests_v4/test_entrypoints.py @@ -2,6 +2,7 @@ from __future__ import annotations import subprocess import sys +from pathlib import Path import unittest import pytest @@ -25,6 +26,19 @@ def _is_astrbot_sdk_installed_in_site_packages() -> bool: return False +def _astr_console_script() -> str | None: + scripts_dir = Path(sys.executable).resolve().parent + candidates = [ + scripts_dir / "astr", + scripts_dir / "astr.exe", + scripts_dir / "astr.cmd", + ] + for candidate in candidates: + if candidate.exists(): + return str(candidate) + return None + + @pytest.mark.integration @pytest.mark.skipif( not _is_astrbot_sdk_installed_in_site_packages(), @@ -60,3 +74,17 @@ class EntryPointTest(unittest.TestCase): ) self.assertEqual(process.returncode, 0, process.stderr) self.assertIn("--plugins-dir", process.stdout) + + def test_console_script_help(self) -> None: + console_script = _astr_console_script() + if console_script is None: + self.fail("astr console script not found") + + process = subprocess.run( + [console_script, "--help"], + capture_output=True, + text=True, + check=False, + ) + self.assertEqual(process.returncode, 0, process.stderr) + self.assertIn("Usage", process.stdout) diff --git a/tests_v4/test_runtime.py b/tests_v4/test_runtime.py index 62d517e76..526b874e6 100644 --- a/tests_v4/test_runtime.py +++ b/tests_v4/test_runtime.py @@ -1,7 +1,6 @@ from __future__ import annotations import asyncio -import shutil import tempfile import unittest from pathlib import Path @@ -10,11 +9,11 @@ from astrbot_sdk.protocol.messages import InitializeOutput, PeerInfo from astrbot_sdk.runtime.bootstrap import SupervisorRuntime from astrbot_sdk.runtime.peer import Peer -from tests_v4.helpers import FakeEnvManager, make_transport_pair - - -def sample_plugin_dir(name: str) -> Path: - return Path(__file__).resolve().parents[1] / "test_plugin" / name +from tests_v4.helpers import ( + FakeEnvManager, + copy_sample_plugin, + make_transport_pair, +) class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): @@ -50,7 +49,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - shutil.copytree(sample_plugin_dir("new"), plugin_root) + copy_sample_plugin("new", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, @@ -86,7 +85,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - shutil.copytree(sample_plugin_dir("new"), plugin_root) + copy_sample_plugin("new", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, @@ -157,7 +156,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - shutil.copytree(sample_plugin_dir("new"), plugin_root) + copy_sample_plugin("new", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, @@ -194,7 +193,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - shutil.copytree(sample_plugin_dir("new"), plugin_root) + copy_sample_plugin("new", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, @@ -237,7 +236,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - shutil.copytree(sample_plugin_dir("new"), plugin_root) + copy_sample_plugin("new", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, @@ -262,7 +261,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "compat_plugin" - shutil.copytree(Path.cwd() / "test_plugin" / "old", plugin_root) + copy_sample_plugin("old", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, @@ -299,7 +298,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "compat_plugin" - shutil.copytree(Path.cwd() / "test_plugin" / "old", plugin_root) + copy_sample_plugin("old", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, @@ -382,7 +381,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "compat_plugin" - shutil.copytree(Path.cwd() / "test_plugin" / "old", plugin_root) + copy_sample_plugin("old", plugin_root, ascii_only=True) runtime = SupervisorRuntime( transport=self.right, diff --git a/tests_v4/test_supervisor_migration.py b/tests_v4/test_supervisor_migration.py index c815138b8..7e283fe96 100644 --- a/tests_v4/test_supervisor_migration.py +++ b/tests_v4/test_supervisor_migration.py @@ -1,82 +1,52 @@ from __future__ import annotations import asyncio -import sys import tempfile -import textwrap import unittest from pathlib import Path +import yaml + from astrbot_sdk.protocol.messages import InitializeOutput, PeerInfo from astrbot_sdk.runtime.bootstrap import SupervisorRuntime from astrbot_sdk.runtime.loader import discover_plugins from astrbot_sdk.runtime.peer import Peer -from tests_v4.helpers import FakeEnvManager, make_transport_pair +from tests_v4.helpers import FakeEnvManager, copy_sample_plugin, make_transport_pair -def write_plugin( +def prepare_sample_plugin( root: Path, folder_name: str, *, + sample_name: str = "new", plugin_name: str | None = None, python_version: str | None = None, include_requirements: bool = True, - reply_text: str | None = None, ) -> Path: - plugin_dir = root / folder_name - commands_dir = plugin_dir / "commands" - commands_dir.mkdir(parents=True, exist_ok=True) - (commands_dir / "__init__.py").write_text("", encoding="utf-8") - - if python_version is None: - python_version = f"{sys.version_info.major}.{sys.version_info.minor}" - - manifest_lines = [ - "_schema_version: 2", - f"name: {plugin_name or folder_name}", - f"display_name: {folder_name}", - "desc: test plugin", - "author: tester", - "version: 0.1.0", - ] - if python_version != "__missing__": - manifest_lines.extend( - [ - "runtime:", - f' python: "{python_version}"', - ] - ) - manifest_lines.extend( - [ - "components:", - " - class: commands.sample:SamplePlugin", - " type: command", - " name: hello", - " description: hello", - ] - ) - (plugin_dir / "plugin.yaml").write_text( - "\n".join(manifest_lines) + "\n", encoding="utf-8" - ) - if include_requirements: - (plugin_dir / "requirements.txt").write_text("", encoding="utf-8") - - text = reply_text or f"{plugin_name or folder_name} handled" - (commands_dir / "sample.py").write_text( - textwrap.dedent( - f"""\ - from astrbot_sdk import Context, MessageEvent, Star, on_command - - - class SamplePlugin(Star): - @on_command("hello") - async def hello(self, event: MessageEvent, ctx: Context): - await event.reply({text!r}) - """ - ), + plugin_dir = copy_sample_plugin(sample_name, root / folder_name, ascii_only=True) + manifest_path = plugin_dir / "plugin.yaml" + manifest = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) or {} + manifest["name"] = plugin_name or folder_name + manifest["display_name"] = folder_name + if python_version == "__missing__": + manifest.pop("runtime", None) + elif python_version is not None: + manifest["runtime"] = {"python": python_version} + manifest_path.write_text( + yaml.safe_dump(manifest, allow_unicode=True, sort_keys=False), encoding="utf-8", ) + requirements_path = plugin_dir / "requirements.txt" + if include_requirements: + requirements_path.write_text( + requirements_path.read_text(encoding="utf-8") + if requirements_path.exists() + else "", + encoding="utf-8", + ) + elif requirements_path.exists(): + requirements_path.unlink() return plugin_dir @@ -84,14 +54,14 @@ class PluginDiscoveryMigrationTest(unittest.TestCase): def test_discover_plugins_keeps_old_supervisor_filtering_rules(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: root = Path(temp_dir) - write_plugin(root, "plugin_one", plugin_name="plugin_one") - write_plugin( + prepare_sample_plugin(root, "plugin_one", plugin_name="plugin_one") + prepare_sample_plugin( root, "plugin_two", plugin_name="plugin_two", python_version="__missing__", ) - write_plugin( + prepare_sample_plugin( root, "plugin_three", plugin_name="plugin_three", @@ -132,17 +102,15 @@ class SupervisorMigrationTest(unittest.IsolatedAsyncioTestCase): ) -> None: with tempfile.TemporaryDirectory() as temp_dir: plugins_dir = Path(temp_dir) / "plugins" - write_plugin( + prepare_sample_plugin( plugins_dir, "plugin_one", plugin_name="plugin_one", - reply_text="plugin_one handled", ) - write_plugin( + prepare_sample_plugin( plugins_dir, "plugin_two", plugin_name="plugin_two", - reply_text="plugin_two handled", ) runtime = SupervisorRuntime( @@ -160,7 +128,7 @@ class SupervisorMigrationTest(unittest.IsolatedAsyncioTestCase): self.assertEqual( self.core.remote_metadata["plugins"], ["plugin_one", "plugin_two"] ) - self.assertEqual(len(self.core.remote_handlers), 2) + self.assertEqual(len(self.core.remote_handlers), 18) handler_id = next( item.id @@ -184,7 +152,7 @@ class SupervisorMigrationTest(unittest.IsolatedAsyncioTestCase): texts = [ item.get("text") for item in runtime.capability_router.sent_messages ] - self.assertEqual(texts, ["plugin_two handled"]) + self.assertEqual(texts, ["Echo: /hello", "Echo: stream"]) finally: await runtime.stop() From 24c71828b334c3d5d8bc52f0fee515379aee9e54 Mon Sep 17 00:00:00 2001 From: letr Date: Fri, 13 Mar 2026 16:58:50 +0800 Subject: [PATCH 3/3] fix: preserve unicode sample fixtures in runtime tests --- src-new/astrbot_sdk/runtime/bootstrap.py | 2 ++ tests_v4/test_entrypoints.py | 23 ++++++++++++++--------- tests_v4/test_runtime.py | 16 ++++++++-------- tests_v4/test_supervisor_migration.py | 17 ++++++++++++++--- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src-new/astrbot_sdk/runtime/bootstrap.py b/src-new/astrbot_sdk/runtime/bootstrap.py index 4ce2357d8..84ce1467c 100644 --- a/src-new/astrbot_sdk/runtime/bootstrap.py +++ b/src-new/astrbot_sdk/runtime/bootstrap.py @@ -187,6 +187,8 @@ class WorkerSession: if existing_pythonpath else repo_src_dir ) + env.setdefault("PYTHONIOENCODING", "utf-8") + env.setdefault("PYTHONUTF8", "1") transport = StdioTransport( command=[ diff --git a/tests_v4/test_entrypoints.py b/tests_v4/test_entrypoints.py index c06a7193b..7d1b2c86e 100644 --- a/tests_v4/test_entrypoints.py +++ b/tests_v4/test_entrypoints.py @@ -27,15 +27,20 @@ def _is_astrbot_sdk_installed_in_site_packages() -> bool: def _astr_console_script() -> str | None: - scripts_dir = Path(sys.executable).resolve().parent - candidates = [ - scripts_dir / "astr", - scripts_dir / "astr.exe", - scripts_dir / "astr.cmd", - ] - for candidate in candidates: - if candidate.exists(): - return str(candidate) + executable_dir = Path(sys.executable).resolve().parent + search_dirs = [executable_dir] + if executable_dir.name.lower() != "scripts": + search_dirs.append(executable_dir / "Scripts") + + for scripts_dir in search_dirs: + candidates = [ + scripts_dir / "astr", + scripts_dir / "astr.exe", + scripts_dir / "astr.cmd", + ] + for candidate in candidates: + if candidate.exists(): + return str(candidate) return None diff --git a/tests_v4/test_runtime.py b/tests_v4/test_runtime.py index 526b874e6..de1127fd1 100644 --- a/tests_v4/test_runtime.py +++ b/tests_v4/test_runtime.py @@ -49,7 +49,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - copy_sample_plugin("new", plugin_root, ascii_only=True) + copy_sample_plugin("new", plugin_root) runtime = SupervisorRuntime( transport=self.right, @@ -85,7 +85,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - copy_sample_plugin("new", plugin_root, ascii_only=True) + copy_sample_plugin("new", plugin_root) runtime = SupervisorRuntime( transport=self.right, @@ -156,7 +156,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - copy_sample_plugin("new", plugin_root, ascii_only=True) + copy_sample_plugin("new", plugin_root) runtime = SupervisorRuntime( transport=self.right, @@ -193,7 +193,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - copy_sample_plugin("new", plugin_root, ascii_only=True) + copy_sample_plugin("new", plugin_root) runtime = SupervisorRuntime( transport=self.right, @@ -236,7 +236,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "v4_plugin" - copy_sample_plugin("new", plugin_root, ascii_only=True) + copy_sample_plugin("new", plugin_root) runtime = SupervisorRuntime( transport=self.right, @@ -261,7 +261,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "compat_plugin" - copy_sample_plugin("old", plugin_root, ascii_only=True) + copy_sample_plugin("old", plugin_root) runtime = SupervisorRuntime( transport=self.right, @@ -298,7 +298,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "compat_plugin" - copy_sample_plugin("old", plugin_root, ascii_only=True) + copy_sample_plugin("old", plugin_root) runtime = SupervisorRuntime( transport=self.right, @@ -381,7 +381,7 @@ class RuntimeIntegrationTest(unittest.IsolatedAsyncioTestCase): with tempfile.TemporaryDirectory() as temp_dir: plugins_root = Path(temp_dir) / "plugins" plugin_root = plugins_root / "compat_plugin" - copy_sample_plugin("old", plugin_root, ascii_only=True) + copy_sample_plugin("old", plugin_root) runtime = SupervisorRuntime( transport=self.right, diff --git a/tests_v4/test_supervisor_migration.py b/tests_v4/test_supervisor_migration.py index 7e283fe96..aceafb950 100644 --- a/tests_v4/test_supervisor_migration.py +++ b/tests_v4/test_supervisor_migration.py @@ -24,7 +24,7 @@ def prepare_sample_plugin( python_version: str | None = None, include_requirements: bool = True, ) -> Path: - plugin_dir = copy_sample_plugin(sample_name, root / folder_name, ascii_only=True) + plugin_dir = copy_sample_plugin(sample_name, root / folder_name) manifest_path = plugin_dir / "plugin.yaml" manifest = yaml.safe_load(manifest_path.read_text(encoding="utf-8")) or {} manifest["name"] = plugin_name or folder_name @@ -128,12 +128,23 @@ class SupervisorMigrationTest(unittest.IsolatedAsyncioTestCase): self.assertEqual( self.core.remote_metadata["plugins"], ["plugin_one", "plugin_two"] ) - self.assertEqual(len(self.core.remote_handlers), 18) + plugin_one_handlers = [ + item.id + for item in self.core.remote_handlers + if item.id.startswith("plugin_one:") + ] + plugin_two_handlers = [ + item.id + for item in self.core.remote_handlers + if item.id.startswith("plugin_two:") + ] + self.assertTrue(plugin_one_handlers) + self.assertTrue(plugin_two_handlers) handler_id = next( item.id for item in self.core.remote_handlers - if item.id.startswith("plugin_two:") + if item.id.startswith("plugin_two:") and item.id.endswith(".hello") ) await self.core.invoke( "handler.invoke",