From 8cfc5d373bd009a3666ad38f5593cb482e9ffaa0 Mon Sep 17 00:00:00 2001
From: worldmozara <worldmozara@163.com>
Date: Sun, 25 Jun 2023 22:32:20 +0800
Subject: [PATCH 1/4] =?UTF-8?q?:sparkles:=20Feature:=20=E6=B7=BB=E5=8A=A0?=
 =?UTF-8?q?=20`inherit=5Fsupported=5Fadapters`=20=E7=94=A8=E4=BA=8E?=
 =?UTF-8?q?=E5=8A=A8=E6=80=81=E7=BB=A7=E6=89=BF=E6=94=AF=E6=8C=81=E9=80=82?=
 =?UTF-8?q?=E9=85=8D=E5=99=A8=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nonebot/plugin/__init__.py |  1 +
 nonebot/plugin/load.py     | 40 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/nonebot/plugin/__init__.py b/nonebot/plugin/__init__.py
index b973d37825aa..4f0df882dd4f 100644
--- a/nonebot/plugin/__init__.py
+++ b/nonebot/plugin/__init__.py
@@ -134,3 +134,4 @@ def get_available_plugin_names() -> Set[str]:
 from .load import load_all_plugins as load_all_plugins
 from .load import load_builtin_plugin as load_builtin_plugin
 from .load import load_builtin_plugins as load_builtin_plugins
+from .load import inherit_supported_adapters as inherit_supported_adapters
diff --git a/nonebot/plugin/load.py b/nonebot/plugin/load.py
index 8e83b1eab0d9..1bc74af364f2 100644
--- a/nonebot/plugin/load.py
+++ b/nonebot/plugin/load.py
@@ -182,3 +182,43 @@ def require(name: str) -> ModuleType:
     if not plugin:
         raise RuntimeError(f'Cannot load plugin "{name}"!')
     return plugin.module
+
+
+def inherit_supported_adapters(*names: str) -> Optional[Set[str]]:
+    """获取已加载插件的适配器支持状态集合。
+
+    如果传入了多个插件名称,返回值会自动取交集。
+
+    参数:
+        names: 插件名称列表。
+
+    异常:
+        RuntimeError: 插件未加载
+        ValueError: 插件缺少元数据
+    """
+    final_supported: Optional[Set[str]] = None
+
+    for name in names:
+        plugin = get_plugin(_module_name_to_plugin_name(name))
+        if plugin is None:
+            raise RuntimeError(f'Plugin "{name}" is not loaded!')
+        meta = plugin.metadata
+        if meta is None:
+            raise ValueError(f'Plugin "{name}" has no metadata!')
+        support = meta.supported_adapters
+        if support is None:
+            continue
+        final_supported = (
+            support if final_supported is None else (final_supported & support)
+        )
+
+    return (
+        final_supported
+        if final_supported is None
+        else {
+            f"~{adapter_name[17:]}"  # strip full name
+            if adapter_name.startswith("nonebot.adapters.")
+            else adapter_name
+            for adapter_name in final_supported
+        }
+    )

From 9633c10c292b36068911c997908378cef95a72e1 Mon Sep 17 00:00:00 2001
From: worldmozara <worldmozara@163.com>
Date: Sun, 25 Jun 2023 23:42:25 +0800
Subject: [PATCH 2/4] =?UTF-8?q?:white=5Fcheck=5Fmark:=20=E4=B8=BA=20`inher?=
 =?UTF-8?q?it=5Fsupported=5Fadapters`=20=E6=B7=BB=E5=8A=A0=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 tests/plugins/metadata_2.py    | 11 +++++++++++
 tests/test_plugin/test_load.py | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 tests/plugins/metadata_2.py

diff --git a/tests/plugins/metadata_2.py b/tests/plugins/metadata_2.py
new file mode 100644
index 000000000000..8cf4cb005440
--- /dev/null
+++ b/tests/plugins/metadata_2.py
@@ -0,0 +1,11 @@
+from nonebot.plugin import PluginMetadata
+
+__plugin_meta__ = PluginMetadata(
+    name="测试插件2",
+    description="测试继承适配器",
+    usage="无法使用",
+    type="application",
+    homepage="https://nonebot.dev",
+    supported_adapters={"~onebot.v11", "~onebot.v12"},
+    extra={"author": "NoneBot"},
+)
diff --git a/tests/test_plugin/test_load.py b/tests/test_plugin/test_load.py
index fcbf35867111..aa646dba989d 100644
--- a/tests/test_plugin/test_load.py
+++ b/tests/test_plugin/test_load.py
@@ -6,7 +6,7 @@
 import pytest
 
 import nonebot
-from nonebot.plugin import Plugin, PluginManager, _managers
+from nonebot.plugin import Plugin, PluginManager, _managers, inherit_supported_adapters
 
 
 @pytest.mark.asyncio
@@ -147,3 +147,32 @@ async def test_plugin_metadata():
     }
 
     assert plugin.metadata.get_supported_adapters() == {FakeAdapter}
+
+
+@pytest.mark.asyncio
+async def test_inherit_supported_adapters():
+    with pytest.raises(RuntimeError):
+        inherit_supported_adapters("some_plugin_not_exist")
+
+    with pytest.raises(ValueError, match="has no metadata!"):
+        inherit_supported_adapters("export")
+
+    echo = nonebot.get_plugin("echo")
+    assert echo
+    assert echo.metadata
+    assert inherit_supported_adapters("echo") is None
+
+    plugin_1 = nonebot.get_plugin("metadata")
+    assert plugin_1
+    assert plugin_1.metadata
+    assert (
+        inherit_supported_adapters("metadata") == plugin_1.metadata.supported_adapters
+    )
+
+    plugin_2 = nonebot.get_plugin("metadata_2")
+    assert plugin_2
+    assert plugin_2.metadata
+    assert inherit_supported_adapters("metadata", "metadata_2") == {"~onebot.v11"}
+    assert inherit_supported_adapters("metadata", "echo", "metadata_2") == {
+        "~onebot.v11"
+    }

From a181cc639a13bf5c527ebc5ce67a7404db07a742 Mon Sep 17 00:00:00 2001
From: worldmozara <worldmozara@163.com>
Date: Mon, 26 Jun 2023 13:33:55 +0800
Subject: [PATCH 3/4] =?UTF-8?q?:white=5Fcheck=5Fmark:=20=E5=B1=95=E5=BC=80?=
 =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=B8=AD=E7=9A=84=E9=80=82=E9=85=8D=E5=99=A8?=
 =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=90=8D=E7=BC=A9=E5=86=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nonebot/plugin/load.py         |  4 +---
 tests/test_plugin/test_load.py | 13 ++++++++-----
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/nonebot/plugin/load.py b/nonebot/plugin/load.py
index 1bc74af364f2..01548165de9e 100644
--- a/nonebot/plugin/load.py
+++ b/nonebot/plugin/load.py
@@ -216,9 +216,7 @@ def inherit_supported_adapters(*names: str) -> Optional[Set[str]]:
         final_supported
         if final_supported is None
         else {
-            f"~{adapter_name[17:]}"  # strip full name
-            if adapter_name.startswith("nonebot.adapters.")
-            else adapter_name
+            adapter_name.replace("~", "nonebot.adapters.", 1)
             for adapter_name in final_supported
         }
     )
diff --git a/tests/test_plugin/test_load.py b/tests/test_plugin/test_load.py
index aa646dba989d..b297deb233f0 100644
--- a/tests/test_plugin/test_load.py
+++ b/tests/test_plugin/test_load.py
@@ -165,14 +165,17 @@ async def test_inherit_supported_adapters():
     plugin_1 = nonebot.get_plugin("metadata")
     assert plugin_1
     assert plugin_1.metadata
-    assert (
-        inherit_supported_adapters("metadata") == plugin_1.metadata.supported_adapters
-    )
+    assert inherit_supported_adapters("metadata") == {
+        "nonebot.adapters.onebot.v11",
+        "plugins.metadata:FakeAdapter",
+    }
 
     plugin_2 = nonebot.get_plugin("metadata_2")
     assert plugin_2
     assert plugin_2.metadata
-    assert inherit_supported_adapters("metadata", "metadata_2") == {"~onebot.v11"}
+    assert inherit_supported_adapters("metadata", "metadata_2") == {
+        "nonebot.adapters.onebot.v11"
+    }
     assert inherit_supported_adapters("metadata", "echo", "metadata_2") == {
-        "~onebot.v11"
+        "nonebot.adapters.onebot.v11"
     }

From cf0ccb5eb45c584f28441672ba66a5e9388c107a Mon Sep 17 00:00:00 2001
From: worldmozara <worldmozara@163.com>
Date: Tue, 27 Jun 2023 12:35:13 +0800
Subject: [PATCH 4/4] =?UTF-8?q?:recycle:=20=E8=B0=83=E6=95=B4=E7=9B=B8?=
 =?UTF-8?q?=E5=85=B3=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nonebot/plugin/load.py | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/nonebot/plugin/load.py b/nonebot/plugin/load.py
index 01548165de9e..375fb205b434 100644
--- a/nonebot/plugin/load.py
+++ b/nonebot/plugin/load.py
@@ -212,11 +212,9 @@ def inherit_supported_adapters(*names: str) -> Optional[Set[str]]:
             support if final_supported is None else (final_supported & support)
         )
 
-    return (
-        final_supported
-        if final_supported is None
-        else {
-            adapter_name.replace("~", "nonebot.adapters.", 1)
-            for adapter_name in final_supported
-        }
-    )
+    return final_supported and {
+        f"nonebot.adapters.{adapter_name[1:]}"
+        if adapter_name.startswith("~")
+        else adapter_name
+        for adapter_name in final_supported
+    }