diff --git a/nonebot/plugin/load.py b/nonebot/plugin/load.py index e561a040..04107c0f 100644 --- a/nonebot/plugin/load.py +++ b/nonebot/plugin/load.py @@ -8,11 +8,13 @@ FrontMatter: """ from collections.abc import Iterable +from itertools import chain import json from pathlib import Path from types import ModuleType from typing import Optional, Union +from nonebot.log import logger from nonebot.utils import path_to_module_name from . import _managers, _module_name_to_plugin_id, get_plugin @@ -108,6 +110,19 @@ def load_from_toml(file_path: str, encoding: str = "utf-8") -> set[Plugin]: encoding: 指定 toml 文件编码 用法: + 新格式: + + ```toml title=pyproject.toml + [tool.nonebot] + plugin_dirs = ["some_dir"] + + [tool.nonebot.plugins] + some-store-plugin = ["some_store_plugin"] + "@local" = ["some_local_plugin"] + ``` + + 旧格式: + ```toml title=pyproject.toml [tool.nonebot] plugins = ["some_plugin"] @@ -126,11 +141,22 @@ def load_from_toml(file_path: str, encoding: str = "utf-8") -> set[Plugin]: raise ValueError("Cannot find '[tool.nonebot]' in given toml file!") if not isinstance(nonebot_data, dict): raise TypeError("'[tool.nonebot]' must be a Table!") - plugins = nonebot_data.get("plugins", []) + plugins = nonebot_data.get("plugins", {}) plugin_dirs = nonebot_data.get("plugin_dirs", []) - assert isinstance(plugins, list), "plugins must be a list of plugin name" + assert isinstance(plugins, (list, dict)), ( + "plugins must be a list or a dict of plugin name" + ) assert isinstance(plugin_dirs, list), "plugin_dirs must be a list of directories" - return load_all_plugins(plugins, plugin_dirs) + if isinstance(plugins, list): + logger.warning("Legacy project format found! Upgrade with `nb upgrade-format`.") + return load_all_plugins( + set( + chain.from_iterable(plugins.values()) + if isinstance(plugins, dict) + else plugins + ), + plugin_dirs, + ) def load_builtin_plugin(name: str) -> Optional[Plugin]: diff --git a/tests/plugins.legacy.toml b/tests/plugins.legacy.toml new file mode 100644 index 00000000..686a44eb --- /dev/null +++ b/tests/plugins.legacy.toml @@ -0,0 +1,3 @@ +[tool.nonebot] +plugins = [] +plugin_dirs = [] diff --git a/tests/plugins.toml b/tests/plugins.toml index 686a44eb..2406441d 100644 --- a/tests/plugins.toml +++ b/tests/plugins.toml @@ -1,3 +1,5 @@ [tool.nonebot] -plugins = [] plugin_dirs = [] + +[tool.nonebot.plugins] +"@local" = [] diff --git a/tests/test_plugin/test_load.py b/tests/test_plugin/test_load.py index 8309268f..89cf72da 100644 --- a/tests/test_plugin/test_load.py +++ b/tests/test_plugin/test_load.py @@ -93,6 +93,8 @@ def test_load_json(): @_recover def test_load_toml(): + nonebot.load_from_toml("./plugins.legacy.toml") + nonebot.load_from_toml("./plugins.toml") with pytest.raises(ValueError, match="Cannot find"): diff --git a/website/docs/editor-support.md b/website/docs/editor-support.md index 0d2f96d6..9535aa89 100644 --- a/website/docs/editor-support.md +++ b/website/docs/editor-support.md @@ -5,7 +5,62 @@ description: 配置编辑器以获得最佳体验 # 编辑器支持 -框架基于 [PEP484](https://www.python.org/dev/peps/pep-0484/)、[PEP 561](https://www.python.org/dev/peps/pep-0561/)、[PEP8](https://www.python.org/dev/peps/pep-0008/) 等规范进行开发并且**拥有完整类型注解**。框架使用 Pyright(Pylance)工具进行类型检查,确保代码可以被编辑器正确解析。 +框架基于 [PEP 484](https://www.python.org/dev/peps/pep-0484/)、[PEP 561](https://www.python.org/dev/peps/pep-0561/)、[PEP 8](https://www.python.org/dev/peps/pep-0008/) 等规范进行开发并且**拥有完整类型注解**。框架使用 Pyright(Pylance)工具进行类型检查,确保代码可以被编辑器正确解析。 + +## CLI 脚手架提供的编辑器工具支持 + +在使用 NB-CLI [创建项目](./quick-start.mdx#创建项目)时,如果选择了用于插件开发的 `simple` 模板,其会根据选择的开发工具,**自动配置项目根目录下的 `.vscode/extensions.json` 文件**,以推荐最匹配的 VS Code 插件,同时自动将相应的预设配置项写入 `pyproject.toml` 作为“开箱即用”配置,从而提升开发体验。 + +```bash +[?] 选择一个要使用的模板: simple (插件开发者) +... +[?] 要使用哪些开发工具? +``` + +### 支持的开发工具 + +1. Pyright (Pylance) + + [VS Code 插件](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) | [项目](https://github.com/microsoft/pyright) | [文档](https://microsoft.github.io/pyright/) + + 由微软开发的 Python 静态类型检查器和语言服务器,提供智能感知、跳转定义、查找引用、实时错误检查等强大功能。 + + 作为 VS Code 官方推荐的 Python 语言服务器,与 Pylance 扩展配合使用,能提供最流畅、最准确的代码补全和类型推断体验,是绝大多数开发者的首选。 + +2. Ruff + + [VS Code 插件](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) | [项目](https://github.com/astral-sh/ruff) | [文档](https://docs.astral.sh/ruff/) + + 一个用 Rust 编写的超快 Python 代码格式化和 lint 工具,完全兼容 `black`、`isort`、`flake8` 等主流工具的规则。 + + 速度极快(比 `black` 和 `flake8` 快 100 倍以上),配置简单,能自动格式化代码并检测潜在错误、代码风格问题(尤其是误用同步网络请求库),是提升代码质量和开发效率的必备利器。 + +3. MyPy + + [VS Code 插件](https://marketplace.visualstudio.com/items?itemName=matangover.mypy) | [项目](https://github.com/python/mypy) | [文档](https://mypy.readthedocs.io/en/stable/index.html) + + 一个官方实现的 Python 静态类型检查器,通过分析代码中的类型注解来发现类型错误。 + +4. BasedPyright + + [VS Code 插件](https://marketplace.visualstudio.com/items?itemName=detachhead.basedpyright) | [项目](https://github.com/DetachHead/basedpyright) | [文档](https://docs.basedpyright.com/) + + 一个基于 Pyright 的、由社区维护的替代性 Python 语言服务器,旨在提供更优的类型检查支持与接近 Pylance 的更好的使用体验。 + + 相较于 Pylance,BasedPyright 允许配合 VS Code 之外的其他编辑器使用,同时也复刻了部分 Pylance 限定的功能。 + + 如果您是高级用户,希望尝试 Pylance 的替代方案,或遇到 Pylance 在特定环境下的兼容性问题,可以考虑使用 BasedPyright。 + +:::caution 提示 +为避免 `Pylance` 和 `BasedPyright` 相互冲突导致配置混乱甚至异常,脚手架默认不允许在创建项目时同时配置这两者。 + +如果确实需要同时使用,请在创建项目时选择 Pylance/Pyright 并根据[相关文档](https://docs.basedpyright.com/latest/installation/ides/#vscode-vscodium)进行手动配置。 +::: + +### 配置效果 + +选择上述工具后,NB-CLI 会在您的项目根目录下生成一个 `.vscode/extensions.json` 文件并在 `pyproject.toml` 文件中写入相应的配置项。当您在 VS Code 中打开此项目时,IDE +会自动弹出提示,建议您安装这些推荐的扩展,一键即可完成开发环境的初始化,让您可以立即开始编写代码,无需手动搜索和安装插件。 ## 编辑器推荐配置 diff --git a/website/docs/quick-start.mdx b/website/docs/quick-start.mdx index 95dfcfeb..2dda48fb 100644 --- a/website/docs/quick-start.mdx +++ b/website/docs/quick-start.mdx @@ -81,8 +81,9 @@ nb create 请注意,多选项使用**空格**选中或取消,**回车**确认。 ```bash - [?] 要使用哪些驱动器? FastAPI (FastAPI 驱动器) [?] 要使用哪些适配器? Console (基于终端的交互式适配器) + [?] 要使用哪些驱动器? FastAPI (FastAPI 驱动器) + [?] 要使用什么本地存储策略? 用户全局 (默认,适用于单用户下单实例) [?] 立即安装依赖? (Y/n) Yes [?] 创建虚拟环境? (Y/n) Yes ``` diff --git a/website/docs/tutorial/create-plugin.md b/website/docs/tutorial/create-plugin.md index 65592876..51a56faa 100644 --- a/website/docs/tutorial/create-plugin.md +++ b/website/docs/tutorial/create-plugin.md @@ -189,12 +189,16 @@ nonebot.load_from_json("plugin_config.json", encoding="utf-8") ### `load_from_toml` -通过 TOML 文件加载插件,是 [`load_all_plugins`](#load_all_plugins) 的 TOML 变种。通过读取 TOML 文件中的 `[tool.nonebot]` Table 中的 `plugins` 和 `plugin_dirs` Array 进行加载。例如: +通过 TOML 文件加载插件,是 [`load_all_plugins`](#load_all_plugins) 的 TOML 变种。通过读取 TOML 文件中的 `[tool.nonebot]` Table 中的 `plugin_dirs` Array 与 +`[tool.nonebot.plugins]` Table 中的多个 Array 进行加载。例如: ```toml title=plugin_config.toml [tool.nonebot] -plugins = ["path.to.your.plugin"] plugin_dirs = ["path/to/your/plugins"] + +[tool.nonebot.plugins] +"@local" = ["path.to.your.plugin"] # 本地插件等非插件商店来源的插件 +"nonebot-plugin-someplugin" = ["nonebot_plugin_someplugin"] # 插件商店来源的插件 ``` ```python diff --git a/website/docs/tutorial/store.mdx b/website/docs/tutorial/store.mdx index 9332ac8e..d21ae1f3 100644 --- a/website/docs/tutorial/store.mdx +++ b/website/docs/tutorial/store.mdx @@ -24,6 +24,9 @@ NoneBot 提供了一个[商店](/store/plugins),商店内容均由社区开发 商店中每个内容的卡片都包含了其名称和简介等信息,点击**卡片右上角**链接图标即可跳转到其主页。 +与此同时,NB-CLI 也提供了一个 TUI 版本的商店界面,可通过 `nb adapter store`、`nb plugin store`、`nb driver store` 命令或 CLI +交互式界面进入。其提供了接近网页商店的体验,同时允许快捷安装到当前项目。 + ## 安装插件