mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-11-27 18:45:05 +08:00
🔀 Merge pull request #691
:construction_workerusing: nb-autodoc to generate api docs
This commit is contained in:
commit
596f763c46
4
.github/workflows/website-deploy.yml
vendored
4
.github/workflows/website-deploy.yml
vendored
@ -25,8 +25,8 @@ jobs:
|
||||
|
||||
- name: Install and build
|
||||
run: |
|
||||
poetry run sphinx-build -M markdown ./docs_build ./build
|
||||
cp -r ./build/markdown/* ./website/docs/api/
|
||||
poetry run nb-autodoc nonebot
|
||||
cp -r ./build/nonebot/* ./website/docs/api/
|
||||
yarn prettier
|
||||
yarn build
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
@ -1,12 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 1
|
||||
id: index
|
||||
slug: /api
|
||||
\-\-\-
|
||||
|
||||
NoneBot 模块
|
||||
===============
|
||||
|
||||
.. automodule:: nonebot
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,43 +0,0 @@
|
||||
\-\-\-
|
||||
id: index
|
||||
slug: /api/adapters/
|
||||
\-\-\-
|
||||
|
||||
NoneBot.adapters 模块
|
||||
=====================
|
||||
|
||||
.. automodule:: nonebot.adapters
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: nonebot.adapters._adapter
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: nonebot.adapters._bot
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: nonebot.adapters._message
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: nonebot.adapters._event
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
||||
|
||||
.. automodule:: nonebot.adapters._template
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
@ -1,82 +0,0 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = "nonebot"
|
||||
copyright = "2020, richardchien"
|
||||
author = "richardchien"
|
||||
|
||||
# The short X.Y version
|
||||
version = "2.0.0"
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = "2.0.0"
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinx.ext.todo",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = "zh_CN"
|
||||
|
||||
master_doc = "README"
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = "alabaster"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
|
||||
# html_baseurl = '/api/'
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# -- Options for autodoc extension ----------------------------------------------
|
||||
autodoc_default_options = {"member-order": "bysource"}
|
||||
autodoc_inherit_docstrings = False
|
||||
autodoc_typehints = "none"
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
@ -1,10 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 2
|
||||
\-\-\-
|
||||
|
||||
NoneBot.config 模块
|
||||
===================
|
||||
|
||||
.. automodule:: nonebot.config
|
||||
:members: Env, Config
|
||||
:show-inheritance:
|
@ -1,11 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 8
|
||||
\-\-\-
|
||||
|
||||
NoneBot.dependencies 模块
|
||||
====================
|
||||
|
||||
.. automodule:: nonebot.dependencies
|
||||
:members:
|
||||
:private-members:
|
||||
:show-inheritance:
|
@ -1,13 +0,0 @@
|
||||
\-\-\-
|
||||
id: index
|
||||
slug: /api/drivers/
|
||||
\-\-\-
|
||||
|
||||
NoneBot.drivers 模块
|
||||
=====================
|
||||
|
||||
.. automodule:: nonebot.drivers
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
@ -1,9 +0,0 @@
|
||||
|
||||
|
||||
NoneBot.drivers.aiohttp 模块
|
||||
=============================
|
||||
|
||||
.. automodule:: nonebot.drivers.aiohttp
|
||||
:members:
|
||||
:private-members:
|
||||
:show-inheritance:
|
@ -1,9 +0,0 @@
|
||||
|
||||
|
||||
NoneBot.drivers.fastapi 模块
|
||||
=============================
|
||||
|
||||
.. automodule:: nonebot.drivers.fastapi
|
||||
:members:
|
||||
:private-members:
|
||||
:show-inheritance:
|
@ -1,9 +0,0 @@
|
||||
|
||||
|
||||
NoneBot.drivers.httpx 模块
|
||||
=============================
|
||||
|
||||
.. automodule:: nonebot.drivers.httpx
|
||||
:members:
|
||||
:private-members:
|
||||
:show-inheritance:
|
@ -1,9 +0,0 @@
|
||||
|
||||
|
||||
NoneBot.drivers.quart 模块
|
||||
==========================
|
||||
|
||||
.. automodule:: nonebot.drivers.quart
|
||||
:members:
|
||||
:private-members:
|
||||
:show-inheritance:
|
@ -1,9 +0,0 @@
|
||||
|
||||
|
||||
NoneBot.drivers.websockets 模块
|
||||
=============================
|
||||
|
||||
.. automodule:: nonebot.drivers.websockets
|
||||
:members:
|
||||
:private-members:
|
||||
:show-inheritance:
|
@ -1,10 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 12
|
||||
\-\-\-
|
||||
|
||||
NoneBot.exception 模块
|
||||
======================
|
||||
|
||||
.. automodule:: nonebot.exception
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,10 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 9
|
||||
\-\-\-
|
||||
|
||||
NoneBot.log 模块
|
||||
=================
|
||||
|
||||
.. automodule:: nonebot.log
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,35 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
@ -1,12 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 5
|
||||
\-\-\-
|
||||
|
||||
NoneBot.matcher 模块
|
||||
====================
|
||||
|
||||
.. automodule:: nonebot.matcher
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members: __init__
|
||||
:show-inheritance:
|
@ -1,10 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 4
|
||||
\-\-\-
|
||||
|
||||
NoneBot.message 模块
|
||||
======================
|
||||
|
||||
.. automodule:: nonebot.message
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,11 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 7
|
||||
\-\-\-
|
||||
|
||||
NoneBot.permission 模块
|
||||
=======================
|
||||
|
||||
.. automodule:: nonebot.permission
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members:
|
@ -1,31 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 3
|
||||
\-\-\-
|
||||
|
||||
NoneBot.plugin 模块
|
||||
====================
|
||||
|
||||
.. automodule:: nonebot.plugin
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __init__
|
||||
|
||||
.. automodule:: nonebot.plugin.plugin
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __init__
|
||||
|
||||
.. automodule:: nonebot.plugin.on
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __init__
|
||||
|
||||
.. automodule:: nonebot.plugin.load
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __init__
|
||||
|
||||
.. automodule:: nonebot.plugin.export
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:special-members: __init__
|
@ -1,11 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 6
|
||||
\-\-\-
|
||||
|
||||
NoneBot.rule 模块
|
||||
====================
|
||||
|
||||
.. automodule:: nonebot.rule
|
||||
:members:
|
||||
:special-members:
|
||||
:show-inheritance:
|
@ -1,10 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 11
|
||||
\-\-\-
|
||||
|
||||
NoneBot.typing 模块
|
||||
===================
|
||||
|
||||
.. automodule:: nonebot.typing
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,10 +0,0 @@
|
||||
\-\-\-
|
||||
sidebar_position: 10
|
||||
\-\-\-
|
||||
|
||||
NoneBot.utils 模块
|
||||
==================
|
||||
|
||||
.. automodule:: nonebot.utils
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,31 +1,37 @@
|
||||
"""
|
||||
"""本模块主要定义了 NoneBot 启动所需函数,供 bot 入口文件调用。
|
||||
|
||||
## 快捷导入
|
||||
|
||||
为方便使用,`nonebot` 模块从子模块导入了部分内容
|
||||
为方便使用,本模块从子模块导入了部分内容,以下内容可以直接通过本模块导入:
|
||||
|
||||
- `on_message` => `nonebot.plugin.on_message`
|
||||
- `on_notice` => `nonebot.plugin.on_notice`
|
||||
- `on_request` => `nonebot.plugin.on_request`
|
||||
- `on_metaevent` => `nonebot.plugin.on_metaevent`
|
||||
- `on_startswith` => `nonebot.plugin.on_startswith`
|
||||
- `on_endswith` => `nonebot.plugin.on_endswith`
|
||||
- `on_keyword` => `nonebot.plugin.on_keyword`
|
||||
- `on_command` => `nonebot.plugin.on_command`
|
||||
- `on_shell_command` => `nonebot.plugin.on_shell_command`
|
||||
- `on_regex` => `nonebot.plugin.on_regex`
|
||||
- `CommandGroup` => `nonebot.plugin.CommandGroup`
|
||||
- `Matchergroup` => `nonebot.plugin.MatcherGroup`
|
||||
- `load_plugin` => `nonebot.plugin.load_plugin`
|
||||
- `load_plugins` => `nonebot.plugin.load_plugins`
|
||||
- `load_all_plugins` => `nonebot.plugin.load_all_plugins`
|
||||
- `load_from_json` => `nonebot.plugin.load_from_json`
|
||||
- `load_from_toml` => `nonebot.plugin.load_from_toml`
|
||||
- `load_builtin_plugin` => `nonebot.plugin.load_builtin_plugin`
|
||||
- `load_builtin_plugins` => `nonebot.plugin.load_builtin_plugins`
|
||||
- `get_plugin` => `nonebot.plugin.get_plugin`
|
||||
- `get_loaded_plugins` => `nonebot.plugin.get_loaded_plugins`
|
||||
- `export` => `nonebot.plugin.export`
|
||||
- `require` => `nonebot.plugin.require`
|
||||
- `on` => {ref}``on` <nonebot.plugin.on.on>`
|
||||
- `on_metaevent` => {ref}``on_metaevent` <nonebot.plugin.on.on_metaevent>`
|
||||
- `on_message` => {ref}``on_message` <nonebot.plugin.on.on_message>`
|
||||
- `on_notice` => {ref}``on_notice` <nonebot.plugin.on.on_notice>`
|
||||
- `on_request` => {ref}``on_request` <nonebot.plugin.on.on_request>`
|
||||
- `on_startswith` => {ref}``on_startswith` <nonebot.plugin.on.on_startswith>`
|
||||
- `on_endswith` => {ref}``on_endswith` <nonebot.plugin.on.on_endswith>`
|
||||
- `on_keyword` => {ref}``on_keyword` <nonebot.plugin.on.on_keyword>`
|
||||
- `on_command` => {ref}``on_command` <nonebot.plugin.on.on_command>`
|
||||
- `on_shell_command` => {ref}``on_shell_command` <nonebot.plugin.on.on_shell_command>`
|
||||
- `on_regex` => {ref}``on_regex` <nonebot.plugin.on.on_regex>`
|
||||
- `CommandGroup` => {ref}``CommandGroup` <nonebot.plugin.on.CommandGroup>`
|
||||
- `Matchergroup` => {ref}``MatcherGroup` <nonebot.plugin.on.MatcherGroup>`
|
||||
- `load_plugin` => {ref}``load_plugin` <nonebot.plugin.load.load_plugin>`
|
||||
- `load_plugins` => {ref}``load_plugins` <nonebot.plugin.load.load_plugins>`
|
||||
- `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>`
|
||||
- `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>`
|
||||
- `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>`
|
||||
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
|
||||
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>`
|
||||
- `get_plugin` => {ref}``get_plugin` <nonebot.plugin.plugin.get_plugin>`
|
||||
- `get_loaded_plugins` => {ref}``get_loaded_plugins` <nonebot.plugin.plugin.get_loaded_plugins>`
|
||||
- `export` => {ref}``export` <nonebot.plugin.export.export>`
|
||||
- `require` => {ref}``require` <nonebot.plugin.load.require>`
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot 模块
|
||||
"""
|
||||
|
||||
import importlib
|
||||
@ -51,14 +57,15 @@ _driver: Optional[Driver] = None
|
||||
|
||||
|
||||
def get_driver() -> Driver:
|
||||
"""
|
||||
获取全局 Driver 对象。可用于在计划任务的回调中获取当前 Driver 对象。
|
||||
"""获取全局 {ref}`nonebot.drivers.Driver` 实例。
|
||||
|
||||
可用于在计划任务的回调等情形中获取当前 {ref}`nonebot.drivers.Driver` 实例。
|
||||
|
||||
返回:
|
||||
Driver: 全局 Driver 对象
|
||||
全局 {ref}`nonebot.drivers.Driver` 对象
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -71,14 +78,14 @@ def get_driver() -> Driver:
|
||||
|
||||
|
||||
def get_app() -> Any:
|
||||
"""
|
||||
获取全局 Driver 对应 Server App 对象。
|
||||
"""获取全局 {ref}`nonebot.drivers.ReverseDriver` 对应的 Server App 对象。
|
||||
|
||||
返回:
|
||||
Any: Server App 对象
|
||||
Server App 对象
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -93,14 +100,14 @@ def get_app() -> Any:
|
||||
|
||||
|
||||
def get_asgi() -> Any:
|
||||
"""
|
||||
获取全局 Driver 对应 Asgi 对象。
|
||||
"""获取全局 {ref}`nonebot.drivers.ReverseDriver` 对应 [ASGI](https://asgi.readthedocs.io/) 对象。
|
||||
|
||||
返回:
|
||||
Any: Asgi 对象
|
||||
ASGI 对象
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -115,23 +122,25 @@ def get_asgi() -> Any:
|
||||
|
||||
|
||||
def get_bot(self_id: Optional[str] = None) -> Bot:
|
||||
"""
|
||||
当提供 self_id 时,此函数是 get_bots()[self_id] 的简写;当不提供时,返回一个 Bot。
|
||||
"""获取一个连接到 NoneBot 的 {ref}`nonebot.adapters._bot.Bot` 对象。
|
||||
|
||||
当提供 `self_id` 时,此函数是 `get_bots()[self_id]` 的简写;
|
||||
当不提供时,返回一个 {ref}`nonebot.adapters._bot.Bot`。
|
||||
|
||||
参数:
|
||||
self_id: 用来识别 Bot 的 ID
|
||||
self_id: 用来识别 {ref}`nonebot.adapters._bot.Bot` 的 {ref}`nonebot.adapters._bot.Bot.self_id` 属性
|
||||
|
||||
返回:
|
||||
Bot: Bot 对象
|
||||
{ref}`nonebot.adapters._bot.Bot` 对象
|
||||
|
||||
异常:
|
||||
KeyError: 对应 ID 的 Bot 不存在
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
ValueError: 没有传入 ID 且没有 Bot 可用
|
||||
KeyError: 对应 self_id 的 Bot 不存在
|
||||
ValueError: 没有传入 self_id 且没有 Bot 可用
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
assert nonebot.get_bot('12345') == nonebot.get_bots()['12345']
|
||||
assert nonebot.get_bot("12345") == nonebot.get_bots()["12345"]
|
||||
|
||||
another_unspecified_bot = nonebot.get_bot()
|
||||
```
|
||||
@ -147,14 +156,13 @@ def get_bot(self_id: Optional[str] = None) -> Bot:
|
||||
|
||||
|
||||
def get_bots() -> Dict[str, Bot]:
|
||||
"""
|
||||
获取所有通过 ws 连接 NoneBot 的 Bot 对象。
|
||||
"""获取所有连接到 NoneBot 的 {ref}`nonebot.adapters._bot.Bot` 对象。
|
||||
|
||||
返回:
|
||||
Dict[str, Bot]: 一个以字符串 ID 为键,Bot 对象为值的字典
|
||||
一个以 {ref}`nonebot.adapters._bot.Bot.self_id` 为键,{ref}`nonebot.adapters._bot.Bot` 对象为值的字典
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -196,17 +204,16 @@ def _resolve_combine_expr(obj_str: str) -> Type[Driver]:
|
||||
return combine_driver(DriverClass, *mixins)
|
||||
|
||||
|
||||
def init(*, _env_file: Optional[str] = None, **kwargs):
|
||||
"""
|
||||
初始化 NoneBot 以及 全局 Driver 对象。
|
||||
def init(*, _env_file: Optional[str] = None, **kwargs: Any) -> None:
|
||||
"""初始化 NoneBot 以及 全局 {ref}`nonebot.drivers.Driver` 对象。
|
||||
|
||||
NoneBot 将会从 .env 文件中读取环境信息,并使用相应的 env 文件配置。
|
||||
|
||||
你也可以传入自定义的 _env_file 来指定 NoneBot 从该文件读取配置。
|
||||
也可以传入自定义的 `_env_file` 来指定 NoneBot 从该文件读取配置。
|
||||
|
||||
参数:
|
||||
_env_file: 配置文件名,默认从 .env.{env_name} 中读取配置
|
||||
**kwargs: 任意变量,将会存储到 Config 对象里
|
||||
_env_file: 配置文件名,默认从 `.env.{env_name}` 中读取配置
|
||||
kwargs: 任意变量,将会存储到 {ref}`nonebot.drivers.Driver.config` 对象里
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -236,12 +243,11 @@ def init(*, _env_file: Optional[str] = None, **kwargs):
|
||||
|
||||
|
||||
def run(*args: Any, **kwargs: Any) -> None:
|
||||
"""
|
||||
启动 NoneBot,即运行全局 Driver 对象。
|
||||
"""启动 NoneBot,即运行全局 {ref}`nonebot.drivers.Driver` 对象。
|
||||
|
||||
参数:
|
||||
*args: 传入 Driver.run 的位置参数
|
||||
**kwargs: 传入 Driver.run 的命名参数
|
||||
args: 传入 {ref}`nonebot.drivers.Driver.run` 的位置参数
|
||||
kwargs: 传入 {ref}`nonebot.drivers.Driver.run` 的命名参数
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -253,6 +259,7 @@ def run(*args: Any, **kwargs: Any) -> None:
|
||||
|
||||
|
||||
import nonebot.params as params
|
||||
from nonebot.plugin import on as on
|
||||
from nonebot.plugin import export as export
|
||||
from nonebot.plugin import require as require
|
||||
from nonebot.plugin import on_regex as on_regex
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""
|
||||
## 协议适配基类
|
||||
"""本模块定义了协议适配基类,各协议请继承以下基类。
|
||||
|
||||
各协议请继承以下基类,并使用 `driver.register_adapter` 注册适配器
|
||||
使用 {ref}`nonebot.drivers.Driver.register_adapter` 注册适配器。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.adapters 模块
|
||||
"""
|
||||
|
||||
from typing import Iterable
|
||||
@ -25,3 +28,11 @@ from ._adapter import Adapter as Adapter
|
||||
from ._message import Message as Message
|
||||
from ._message import MessageSegment as MessageSegment
|
||||
from ._template import MessageTemplate as MessageTemplate
|
||||
|
||||
__autodoc__ = {
|
||||
"_bot": True,
|
||||
"_event": True,
|
||||
"_adapter": True,
|
||||
"_message": True,
|
||||
"_template": True,
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.adapters._adapter 模块
|
||||
"""
|
||||
import abc
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Any, Dict, AsyncGenerator
|
||||
@ -18,56 +23,89 @@ from ._bot import Bot
|
||||
|
||||
|
||||
class Adapter(abc.ABC):
|
||||
"""协议适配器基类。
|
||||
|
||||
通常,在 Adapter 中编写协议通信相关代码,如: 建立通信连接、处理接收与发送 data 等。
|
||||
|
||||
参数:
|
||||
driver: {ref}`nonebot.drivers.Driver` 实例
|
||||
kwargs: 其他由 {ref}`nonebot.drivers.Driver.register_adapter` 传入的额外参数
|
||||
"""
|
||||
|
||||
def __init__(self, driver: Driver, **kwargs: Any):
|
||||
self.driver: Driver = driver
|
||||
"""{ref}`nonebot.drivers.Driver` 实例"""
|
||||
self.bots: Dict[str, Bot] = {}
|
||||
"""本协议适配器已建立连接的 {ref}`nonebot.adapters._bot.Bot` 实例"""
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_name(cls) -> str:
|
||||
"""当前协议适配器的名称"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def config(self) -> Config:
|
||||
"""全局 NoneBot 配置"""
|
||||
return self.driver.config
|
||||
|
||||
def bot_connect(self, bot: Bot) -> None:
|
||||
"""告知 NoneBot 建立了一个新的 {ref}`nonebot.adapters._bot.Bot` 连接。
|
||||
|
||||
当有新的 {ref}`nonebot.adapters._bot.Bot` 实例连接建立成功时调用。
|
||||
|
||||
参数:
|
||||
bot: {ref}`nonebot.adapters._bot.Bot` 实例
|
||||
"""
|
||||
self.driver._bot_connect(bot)
|
||||
self.bots[bot.self_id] = bot
|
||||
|
||||
def bot_disconnect(self, bot: Bot) -> None:
|
||||
"""告知 NoneBot {ref}`nonebot.adapters._bot.Bot` 连接已断开。
|
||||
|
||||
当有 {ref}`nonebot.adapters._bot.Bot` 实例连接断开时调用。
|
||||
|
||||
参数:
|
||||
bot: {ref}`nonebot.adapters._bot.Bot` 实例
|
||||
"""
|
||||
self.driver._bot_disconnect(bot)
|
||||
self.bots.pop(bot.self_id, None)
|
||||
|
||||
def setup_http_server(self, setup: HTTPServerSetup):
|
||||
"""设置一个 HTTP 服务器路由配置"""
|
||||
if not isinstance(self.driver, ReverseDriver):
|
||||
raise TypeError("Current driver does not support http server")
|
||||
self.driver.setup_http_server(setup)
|
||||
|
||||
def setup_websocket_server(self, setup: WebSocketServerSetup):
|
||||
"""设置一个 WebSocket 服务器路由配置"""
|
||||
if not isinstance(self.driver, ReverseDriver):
|
||||
raise TypeError("Current driver does not support websocket server")
|
||||
self.driver.setup_websocket_server(setup)
|
||||
|
||||
async def request(self, setup: Request) -> Response:
|
||||
"""进行一个 HTTP 客户端请求"""
|
||||
if not isinstance(self.driver, ForwardDriver):
|
||||
raise TypeError("Current driver does not support http client")
|
||||
return await self.driver.request(setup)
|
||||
|
||||
@asynccontextmanager
|
||||
async def websocket(self, setup: Request) -> AsyncGenerator[WebSocket, None]:
|
||||
"""建立一个 WebSocket 客户端连接请求"""
|
||||
if not isinstance(self.driver, ForwardDriver):
|
||||
raise TypeError("Current driver does not support websocket client")
|
||||
async with self.driver.websocket(setup) as ws:
|
||||
yield ws
|
||||
|
||||
@abc.abstractmethod
|
||||
async def _call_api(self, bot: Bot, api: str, **data) -> Any:
|
||||
"""
|
||||
`adapter` 实际调用 api 的逻辑实现函数,实现该方法以调用 api。
|
||||
async def _call_api(self, bot: Bot, api: str, **data: Any) -> Any:
|
||||
"""`Adapter` 实际调用 api 的逻辑实现函数,实现该方法以调用 api。
|
||||
|
||||
参数:
|
||||
api: API 名称
|
||||
**data: API 数据
|
||||
data: API 数据
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
__autodoc__ = {"Adapter._call_api": True}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.adapters._bot 模块
|
||||
"""
|
||||
import abc
|
||||
import asyncio
|
||||
from functools import partial
|
||||
@ -21,26 +26,23 @@ class _ApiCall(Protocol):
|
||||
|
||||
|
||||
class Bot(abc.ABC):
|
||||
"""
|
||||
Bot 基类。用于处理上报消息,并提供 API 调用接口。
|
||||
"""Bot 基类。
|
||||
|
||||
用于处理上报消息,并提供 API 调用接口。
|
||||
|
||||
参数:
|
||||
adapter: 协议适配器实例
|
||||
self_id: 机器人 ID
|
||||
"""
|
||||
|
||||
_calling_api_hook: Set[T_CallingAPIHook] = set()
|
||||
"""
|
||||
call_api 时执行的函数
|
||||
"""
|
||||
"""call_api 时执行的函数"""
|
||||
_called_api_hook: Set[T_CalledAPIHook] = set()
|
||||
"""
|
||||
call_api 后执行的函数
|
||||
"""
|
||||
"""call_api 后执行的函数"""
|
||||
|
||||
def __init__(self, adapter: "Adapter", self_id: str):
|
||||
"""
|
||||
参数:
|
||||
self_id: 机器人 ID
|
||||
request: request 连接对象
|
||||
"""
|
||||
self.adapter: "Adapter" = adapter
|
||||
"""协议适配器实例"""
|
||||
self.self_id: str = self_id
|
||||
"""机器人 ID"""
|
||||
|
||||
@ -49,19 +51,20 @@ class Bot(abc.ABC):
|
||||
|
||||
@property
|
||||
def type(self) -> str:
|
||||
"""协议适配器名称"""
|
||||
return self.adapter.get_name()
|
||||
|
||||
@property
|
||||
def config(self) -> Config:
|
||||
"""全局 NoneBot 配置"""
|
||||
return self.adapter.config
|
||||
|
||||
async def call_api(self, api: str, **data: Any) -> Any:
|
||||
"""
|
||||
调用机器人 API 接口,可以通过该函数或直接通过 bot 属性进行调用
|
||||
"""调用机器人 API 接口,可以通过该函数或直接通过 bot 属性进行调用
|
||||
|
||||
参数:
|
||||
api: API 名称
|
||||
**data: API 数据
|
||||
data: API 数据
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -121,41 +124,44 @@ class Bot(abc.ABC):
|
||||
|
||||
@abc.abstractmethod
|
||||
async def send(
|
||||
self, event: "Event", message: Union[str, "Message", "MessageSegment"], **kwargs
|
||||
self,
|
||||
event: "Event",
|
||||
message: Union[str, "Message", "MessageSegment"],
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""
|
||||
调用机器人基础发送消息接口
|
||||
"""调用机器人基础发送消息接口
|
||||
|
||||
参数:
|
||||
event: 上报事件
|
||||
message: 要发送的消息
|
||||
kwargs: 任意额外参数
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def on_calling_api(cls, func: T_CallingAPIHook) -> T_CallingAPIHook:
|
||||
"""
|
||||
调用 api 预处理。
|
||||
"""调用 api 预处理。
|
||||
|
||||
参数:
|
||||
bot: 当前 bot 对象
|
||||
api: 调用的 api 名称
|
||||
data: api 调用的参数字典
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前 bot 对象
|
||||
- api: 调用的 api 名称
|
||||
- data: api 调用的参数字典
|
||||
"""
|
||||
cls._calling_api_hook.add(func)
|
||||
return func
|
||||
|
||||
@classmethod
|
||||
def on_called_api(cls, func: T_CalledAPIHook) -> T_CalledAPIHook:
|
||||
"""
|
||||
调用 api 后处理。
|
||||
"""调用 api 后处理。
|
||||
|
||||
参数:
|
||||
bot: 当前 bot 对象
|
||||
exception: 调用 api 时发生的错误
|
||||
api: 调用的 api 名称
|
||||
data: api 调用的参数字典
|
||||
result: api 调用的返回
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前 bot 对象
|
||||
- exception: 调用 api 时发生的错误
|
||||
- api: 调用的 api 名称
|
||||
- data: api 调用的参数字典
|
||||
- result: api 调用的返回
|
||||
"""
|
||||
cls._called_api_hook.add(func)
|
||||
return func
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.adapters._event 模块
|
||||
"""
|
||||
import abc
|
||||
|
||||
from pydantic import BaseModel
|
||||
@ -16,31 +21,26 @@ class Event(abc.ABC, BaseModel):
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_type(self) -> str:
|
||||
"""
|
||||
获取事件类型的方法,类型通常为 NoneBot 内置的四种类型。
|
||||
"""
|
||||
"""获取事件类型的方法,类型通常为 NoneBot 内置的四种类型。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_event_name(self) -> str:
|
||||
"""
|
||||
获取事件名称的方法。
|
||||
"""
|
||||
"""获取事件名称的方法。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_event_description(self) -> str:
|
||||
"""
|
||||
获取事件描述的方法,通常为事件具体内容。
|
||||
"""
|
||||
"""获取事件描述的方法,通常为事件具体内容。"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"[{self.get_event_name()}]: {self.get_event_description()}"
|
||||
|
||||
def get_log_string(self) -> str:
|
||||
"""
|
||||
获取事件日志信息的方法,通常你不需要修改这个方法,只有当希望 NoneBot 隐藏该事件日志时,可以抛出 `NoLogException` 异常。
|
||||
"""获取事件日志信息的方法。
|
||||
|
||||
通常你不需要修改这个方法,只有当希望 NoneBot 隐藏该事件日志时,可以抛出 `NoLogException` 异常。
|
||||
|
||||
异常:
|
||||
NoLogException
|
||||
@ -49,34 +49,27 @@ class Event(abc.ABC, BaseModel):
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_user_id(self) -> str:
|
||||
"""
|
||||
获取事件主体 id 的方法,通常是用户 id 。
|
||||
"""
|
||||
"""获取事件主体 id 的方法,通常是用户 id 。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_session_id(self) -> str:
|
||||
"""
|
||||
获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。
|
||||
"""
|
||||
"""获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_message(self) -> "Message":
|
||||
"""
|
||||
获取事件消息内容的方法。
|
||||
"""
|
||||
"""获取事件消息内容的方法。"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_plaintext(self) -> str:
|
||||
"""
|
||||
获取消息纯文本的方法,通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
|
||||
"""获取消息纯文本的方法。
|
||||
|
||||
通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
|
||||
"""
|
||||
return self.get_message().extract_plain_text()
|
||||
|
||||
@abc.abstractmethod
|
||||
def is_tome(self) -> bool:
|
||||
"""
|
||||
获取事件是否与机器人有关的方法。
|
||||
"""
|
||||
"""获取事件是否与机器人有关的方法。"""
|
||||
raise NotImplementedError
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.adapters._message 模块
|
||||
"""
|
||||
import abc
|
||||
from copy import deepcopy
|
||||
from dataclasses import field, asdict, dataclass
|
||||
@ -28,17 +33,14 @@ class MessageSegment(Mapping, abc.ABC, Generic[TM]):
|
||||
"""消息段基类"""
|
||||
|
||||
type: str
|
||||
"""
|
||||
消息段类型
|
||||
"""
|
||||
"""消息段类型"""
|
||||
data: Dict[str, Any] = field(default_factory=lambda: {})
|
||||
"""
|
||||
消息段数据
|
||||
"""
|
||||
"""消息段数据"""
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_message_class(cls) -> Type[TM]:
|
||||
"""获取消息数组类型"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
@ -87,11 +89,16 @@ class MessageSegment(Mapping, abc.ABC, Generic[TM]):
|
||||
|
||||
@abc.abstractmethod
|
||||
def is_text(self) -> bool:
|
||||
"""当前消息段是否为纯文本"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Message(List[TMS], abc.ABC):
|
||||
"""消息数组"""
|
||||
"""消息数组
|
||||
|
||||
参数:
|
||||
message: 消息内容
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self: TM,
|
||||
@ -99,10 +106,6 @@ class Message(List[TMS], abc.ABC):
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
参数:
|
||||
message: 消息内容
|
||||
"""
|
||||
super().__init__(*args, **kwargs)
|
||||
if message is None:
|
||||
return
|
||||
@ -115,8 +118,9 @@ class Message(List[TMS], abc.ABC):
|
||||
|
||||
@classmethod
|
||||
def template(cls: Type[TM], format_string: Union[str, TM]) -> MessageTemplate[TM]:
|
||||
"""
|
||||
根据创建消息模板, 用法和 `str.format` 大致相同, 但是可以输出消息对象, 并且支持以 `Message` 对象作为消息模板
|
||||
"""创建消息模板。
|
||||
|
||||
用法和 `str.format` 大致相同, 但是可以输出消息对象, 并且支持以 `Message` 对象作为消息模板
|
||||
|
||||
并且提供了拓展的格式化控制符, 可以用适用于该消息类型的 `MessageSegment` 的工厂方法创建消息
|
||||
|
||||
@ -140,13 +144,14 @@ class Message(List[TMS], abc.ABC):
|
||||
format_string: 格式化字符串
|
||||
|
||||
返回:
|
||||
MessageFormatter[TM]: 消息格式化器
|
||||
消息格式化器
|
||||
"""
|
||||
return MessageTemplate(format_string, cls)
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_segment_class(cls) -> Type[TMS]:
|
||||
"""获取消息段类型"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self):
|
||||
@ -163,6 +168,7 @@ class Message(List[TMS], abc.ABC):
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def _construct(msg: Union[str, Mapping, Iterable[Mapping], Any]) -> Iterable[TMS]:
|
||||
"""构造消息数组"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __add__(self: TM, other: Union[str, Mapping, Iterable[Mapping]]) -> TM:
|
||||
@ -249,8 +255,7 @@ class Message(List[TMS], abc.ABC):
|
||||
return len(self[value]) if isinstance(value, str) else super().count(value)
|
||||
|
||||
def append(self: TM, obj: Union[str, TMS]) -> TM:
|
||||
"""
|
||||
添加一个消息段到消息数组末尾
|
||||
"""添加一个消息段到消息数组末尾。
|
||||
|
||||
参数:
|
||||
obj: 要添加的消息段
|
||||
@ -264,8 +269,7 @@ class Message(List[TMS], abc.ABC):
|
||||
return self
|
||||
|
||||
def extend(self: TM, obj: Union[TM, Iterable[TMS]]) -> TM:
|
||||
"""
|
||||
拼接一个消息数组或多个消息段到消息数组末尾
|
||||
"""拼接一个消息数组或多个消息段到消息数组末尾。
|
||||
|
||||
参数:
|
||||
obj: 要添加的消息数组
|
||||
@ -278,8 +282,9 @@ class Message(List[TMS], abc.ABC):
|
||||
return deepcopy(self)
|
||||
|
||||
def extract_plain_text(self: "Message[MessageSegment]") -> str:
|
||||
"""
|
||||
提取消息内纯文本消息
|
||||
"""
|
||||
"""提取消息内纯文本消息"""
|
||||
|
||||
return "".join(str(seg) for seg in self if seg.is_text())
|
||||
|
||||
|
||||
__autodoc__ = {"MessageSegment.__str__": True}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.adapters._template 模块
|
||||
"""
|
||||
import inspect
|
||||
import functools
|
||||
from string import Formatter
|
||||
@ -31,7 +36,12 @@ FormatSpecFunc_T = TypeVar("FormatSpecFunc_T", bound=FormatSpecFunc)
|
||||
|
||||
|
||||
class MessageTemplate(Formatter, Generic[TF]):
|
||||
"""消息模板格式化实现类"""
|
||||
"""消息模板格式化实现类。
|
||||
|
||||
参数:
|
||||
template: 模板
|
||||
factory: 消息构造类型,默认为 `str`
|
||||
"""
|
||||
|
||||
@overload
|
||||
def __init__(
|
||||
@ -46,13 +56,6 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
...
|
||||
|
||||
def __init__(self, template, factory=str) -> None:
|
||||
"""
|
||||
创建一个模板
|
||||
|
||||
参数:
|
||||
template: 模板
|
||||
factory: 消息构造类型,默认为 `str`
|
||||
"""
|
||||
self.template: TF = template
|
||||
self.factory: Type[TF] = factory
|
||||
self.format_specs: Dict[str, FormatSpecFunc] = {}
|
||||
@ -67,9 +70,7 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
return spec
|
||||
|
||||
def format(self, *args: Any, **kwargs: Any) -> TF:
|
||||
"""
|
||||
根据模板和参数生成消息对象
|
||||
"""
|
||||
"""根据模板和参数生成消息对象"""
|
||||
msg = self.factory()
|
||||
if isinstance(self.template, str):
|
||||
msg += self.vformat(self.template, args, kwargs)
|
||||
|
@ -1,9 +1,12 @@
|
||||
"""
|
||||
## 配置
|
||||
"""本模块定义了 NoneBot 本身运行所需的配置项。
|
||||
|
||||
NoneBot 使用 [`pydantic`](https://pydantic-docs.helpmanual.io/) 以及 [`python-dotenv`](https://saurabh-kumar.com/python-dotenv/) 来读取配置。
|
||||
|
||||
配置项需符合特殊格式或 json 序列化格式。详情见 [`pydantic Field Type`](https://pydantic-docs.helpmanual.io/usage/types/) 文档。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.config 模块
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
@ -11,7 +14,7 @@ from datetime import timedelta
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Any, Set, Dict, Tuple, Union, Mapping, Optional
|
||||
|
||||
from pydantic import BaseSettings, IPvAnyAddress
|
||||
from pydantic import BaseSettings, IPvAnyAddress, validator
|
||||
from pydantic.env_settings import (
|
||||
SettingsError,
|
||||
EnvSettingsSource,
|
||||
@ -121,15 +124,15 @@ class BaseConfig(BaseSettings):
|
||||
|
||||
|
||||
class Env(BaseConfig):
|
||||
"""
|
||||
运行环境配置。大小写不敏感。
|
||||
"""运行环境配置。大小写不敏感。
|
||||
|
||||
将会从 `nonebot.init 参数` > `环境变量` > `.env 环境配置文件` 的优先级读取配置。
|
||||
将会从 `环境变量` > `.env 环境配置文件` 的优先级读取环境信息。
|
||||
"""
|
||||
|
||||
environment: str = "prod"
|
||||
"""
|
||||
当前环境名。 NoneBot 将从 `.env.{environment}` 文件中加载配置。
|
||||
"""当前环境名。
|
||||
|
||||
NoneBot 将从 `.env.{environment}` 文件中加载配置。
|
||||
"""
|
||||
|
||||
class Config:
|
||||
@ -138,36 +141,37 @@ class Env(BaseConfig):
|
||||
|
||||
|
||||
class Config(BaseConfig):
|
||||
"""
|
||||
NoneBot 主要配置。大小写不敏感。
|
||||
"""NoneBot 主要配置。大小写不敏感。
|
||||
|
||||
除了 NoneBot 的配置项外,还可以自行添加配置项到 `.env.{environment}` 文件中。
|
||||
这些配置将会在 json 反序列化后一起带入 `Config` 类中。
|
||||
|
||||
配置方法参考: [配置](https://v2.nonebot.dev/docs/tutorial/configuration)
|
||||
"""
|
||||
|
||||
_common_config: dict
|
||||
_env_file: str
|
||||
_common_config: Dict[str, Any]
|
||||
|
||||
# nonebot configs
|
||||
driver: str = "~fastapi"
|
||||
"""
|
||||
NoneBot 运行所使用的 `Driver` 。继承自 `nonebot.drivers.Driver` 。
|
||||
"""NoneBot 运行所使用的 `Driver` 。继承自 {ref}`nonebot.drivers.Driver` 。
|
||||
|
||||
配置格式为 `<module>[:<Driver>][+<module>[:<Mixin>]]*`。
|
||||
|
||||
`~` 为 `nonebot.drivers.` 的缩写。
|
||||
"""
|
||||
host: IPvAnyAddress = IPv4Address("127.0.0.1") # type: ignore
|
||||
"""
|
||||
NoneBot 的 HTTP 和 WebSocket 服务端监听的 IP/主机名。
|
||||
"""
|
||||
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的 IP/主机名。"""
|
||||
port: int = 8080
|
||||
"""
|
||||
NoneBot 的 HTTP 和 WebSocket 服务端监听的端口。
|
||||
"""
|
||||
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的端口。"""
|
||||
log_level: Union[int, str] = "INFO"
|
||||
"""
|
||||
配置 NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称,参考 [`loguru 日志等级`](https://loguru.readthedocs.io/en/stable/api/logger.html#levels)。
|
||||
"""NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称
|
||||
|
||||
参考 [`loguru 日志等级`](https://loguru.readthedocs.io/en/stable/api/logger.html#levels)。
|
||||
|
||||
:::tip 提示
|
||||
日志等级名称应为大写,如 `INFO`。
|
||||
:::
|
||||
|
||||
用法:
|
||||
```conf
|
||||
@ -178,14 +182,11 @@ class Config(BaseConfig):
|
||||
|
||||
# bot connection configs
|
||||
api_timeout: Optional[float] = 30.0
|
||||
"""
|
||||
API 请求超时时间,单位: 秒。
|
||||
"""
|
||||
"""API 请求超时时间,单位: 秒。"""
|
||||
|
||||
# bot runtime configs
|
||||
superusers: Set[str] = set()
|
||||
"""
|
||||
机器人超级用户。
|
||||
"""机器人超级用户。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
@ -193,20 +194,25 @@ class Config(BaseConfig):
|
||||
```
|
||||
"""
|
||||
nickname: Set[str] = set()
|
||||
"""
|
||||
机器人昵称。
|
||||
"""
|
||||
"""机器人昵称。"""
|
||||
command_start: Set[str] = {"/"}
|
||||
"""
|
||||
命令的起始标记,用于判断一条消息是不是命令。
|
||||
"""命令的起始标记,用于判断一条消息是不是命令。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
COMMAND_START=["/", ""]
|
||||
```
|
||||
"""
|
||||
command_sep: Set[str] = {"."}
|
||||
"""
|
||||
命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。
|
||||
"""命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
COMMAND_SEP=["."]
|
||||
```
|
||||
"""
|
||||
session_expire_timeout: timedelta = timedelta(minutes=2)
|
||||
"""
|
||||
等待用户回复的超时时间。
|
||||
"""等待用户回复的超时时间。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
@ -226,3 +232,9 @@ class Config(BaseConfig):
|
||||
class Config:
|
||||
extra = "allow"
|
||||
env_file = ".env.prod"
|
||||
|
||||
|
||||
__autodoc__ = {
|
||||
"CustomEnvSettings": False,
|
||||
"BaseConfig": False,
|
||||
}
|
||||
|
@ -1,20 +1,42 @@
|
||||
"""本模块包含了 NoneBot 事件处理过程中使用到的常量。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 9
|
||||
description: nonebot.consts 模块
|
||||
"""
|
||||
from typing_extensions import Literal
|
||||
|
||||
# used by Matcher
|
||||
RECEIVE_KEY = "_receive_{id}"
|
||||
LAST_RECEIVE_KEY = "_last_receive"
|
||||
ARG_KEY = "{key}"
|
||||
REJECT_TARGET = "_current_target"
|
||||
REJECT_CACHE_TARGET = "_next_target"
|
||||
RECEIVE_KEY: Literal["_receive_{id}"] = "_receive_{id}"
|
||||
"""`receive` 存储 key"""
|
||||
LAST_RECEIVE_KEY: Literal["_last_receive"] = "_last_receive"
|
||||
"""`last_receive` 存储 key"""
|
||||
ARG_KEY: Literal["{key}"] = "{key}"
|
||||
"""`arg` 存储 key"""
|
||||
REJECT_TARGET: Literal["_current_target"] = "_current_target"
|
||||
"""当前 `reject` 目标存储 key"""
|
||||
REJECT_CACHE_TARGET: Literal["_next_target"] = "_next_target"
|
||||
"""下一个 `reject` 目标存储 key"""
|
||||
|
||||
# used by Rule
|
||||
PREFIX_KEY = "_prefix"
|
||||
PREFIX_KEY: Literal["_prefix"] = "_prefix"
|
||||
"""命令前缀存储 key"""
|
||||
|
||||
CMD_KEY = "command"
|
||||
RAW_CMD_KEY = "raw_command"
|
||||
CMD_ARG_KEY = "command_arg"
|
||||
CMD_KEY: Literal["command"] = "command"
|
||||
"""命令元组存储 key"""
|
||||
RAW_CMD_KEY: Literal["raw_command"] = "raw_command"
|
||||
"""命令文本存储 key"""
|
||||
CMD_ARG_KEY: Literal["command_arg"] = "command_arg"
|
||||
"""命令参数存储 key"""
|
||||
|
||||
SHELL_ARGS = "_args"
|
||||
SHELL_ARGV = "_argv"
|
||||
SHELL_ARGS: Literal["_args"] = "_args"
|
||||
"""shell 命令 parse 后参数字典存储 key"""
|
||||
SHELL_ARGV: Literal["_argv"] = "_argv"
|
||||
"""shell 命令原始参数列表存储 key"""
|
||||
|
||||
REGEX_MATCHED = "_matched"
|
||||
REGEX_GROUP = "_matched_groups"
|
||||
REGEX_DICT = "_matched_dict"
|
||||
REGEX_MATCHED: Literal["_matched"] = "_matched"
|
||||
"""正则匹配结果存储 key"""
|
||||
REGEX_GROUP: Literal["_matched_groups"] = "_matched_groups"
|
||||
"""正则匹配 group 元组存储 key"""
|
||||
REGEX_DICT: Literal["_matched_dict"] = "_matched_dict"
|
||||
"""正则匹配 group 字典存储 key"""
|
||||
|
@ -1,7 +1,8 @@
|
||||
"""
|
||||
## 依赖注入处理模块
|
||||
"""本模块模块实现了依赖注入的定义与处理。
|
||||
|
||||
该模块实现了依赖注入的定义与处理。
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.dependencies 模块
|
||||
"""
|
||||
|
||||
import abc
|
||||
@ -23,6 +24,11 @@ R = TypeVar("R")
|
||||
|
||||
|
||||
class Param(abc.ABC, FieldInfo):
|
||||
"""依赖注入的基本单元 —— 参数。
|
||||
|
||||
继承自 `pydantic.fields.FieldInfo`,用于描述参数信息(不包括参数名)。
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: "Dependent", name: str, param: inspect.Parameter
|
||||
@ -45,6 +51,16 @@ class CustomConfig(BaseConfig):
|
||||
|
||||
|
||||
class Dependent(Generic[R]):
|
||||
"""依赖注入容器
|
||||
|
||||
参数:
|
||||
call: 依赖注入的可调用对象,可以是任何 Callable 对象
|
||||
pre_checkers: 依赖注入解析前的参数检查
|
||||
params: 具名参数列表
|
||||
parameterless: 匿名参数列表
|
||||
allow_types: 允许的参数类型
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@ -192,3 +208,6 @@ class Dependent(Generic[R]):
|
||||
values[field.name] = value
|
||||
|
||||
return values
|
||||
|
||||
|
||||
__autodoc__ = {"CustomConfig": False}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.dependencies.utils 模块
|
||||
"""
|
||||
import inspect
|
||||
from typing import Any, Dict, Callable
|
||||
|
||||
@ -6,6 +11,7 @@ from pydantic.typing import ForwardRef, evaluate_forwardref
|
||||
|
||||
|
||||
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
||||
"""获取可调用对象签名"""
|
||||
signature = inspect.signature(call)
|
||||
globalns = getattr(call, "__globals__", {})
|
||||
typed_params = [
|
||||
@ -22,6 +28,7 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
||||
|
||||
|
||||
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any:
|
||||
"""获取参数的类型注解"""
|
||||
annotation = param.annotation
|
||||
if isinstance(annotation, str):
|
||||
annotation = ForwardRef(annotation)
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""
|
||||
## 后端驱动适配基类
|
||||
"""本模块定义了驱动适配器基类。
|
||||
|
||||
各驱动请继承以下基类
|
||||
各驱动请继承以下基类。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.drivers 模块
|
||||
"""
|
||||
|
||||
import abc
|
||||
@ -35,57 +38,38 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class Driver(abc.ABC):
|
||||
"""
|
||||
Driver 基类。
|
||||
"""Driver 基类。
|
||||
|
||||
参数:
|
||||
env: 包含环境信息的 Env 对象
|
||||
config: 包含配置信息的 Config 对象
|
||||
"""
|
||||
|
||||
_adapters: Dict[str, "Adapter"] = {}
|
||||
"""
|
||||
已注册的适配器列表
|
||||
"""
|
||||
"""已注册的适配器列表"""
|
||||
_bot_connection_hook: Set[T_BotConnectionHook] = set()
|
||||
"""
|
||||
Bot 连接建立时执行的函数
|
||||
"""
|
||||
"""Bot 连接建立时执行的函数"""
|
||||
_bot_disconnection_hook: Set[T_BotDisconnectionHook] = set()
|
||||
"""
|
||||
Bot 连接断开时执行的函数
|
||||
"""
|
||||
"""Bot 连接断开时执行的函数"""
|
||||
|
||||
def __init__(self, env: Env, config: Config):
|
||||
"""
|
||||
参数:
|
||||
env: 包含环境信息的 Env 对象
|
||||
config: 包含配置信息的 Config 对象
|
||||
"""
|
||||
self.env: str = env.environment
|
||||
"""
|
||||
环境名称
|
||||
"""
|
||||
"""环境名称"""
|
||||
self.config: Config = config
|
||||
"""
|
||||
配置对象
|
||||
"""
|
||||
"""全局配置对象"""
|
||||
self._clients: Dict[str, "Bot"] = {}
|
||||
"""
|
||||
已连接的 Bot
|
||||
"""
|
||||
|
||||
@property
|
||||
def bots(self) -> Dict[str, "Bot"]:
|
||||
"""
|
||||
获取当前所有已连接的 Bot
|
||||
"""
|
||||
"""获取当前所有已连接的 Bot"""
|
||||
return self._clients
|
||||
|
||||
def register_adapter(self, adapter: Type["Adapter"], **kwargs) -> None:
|
||||
"""
|
||||
注册一个协议适配器
|
||||
"""注册一个协议适配器
|
||||
|
||||
参数:
|
||||
name: 适配器名称,用于在连接时进行识别
|
||||
adapter: 适配器 Class
|
||||
**kwargs: 其他传递给适配器的参数
|
||||
adapter: 适配器类
|
||||
kwargs: 其他传递给适配器的参数
|
||||
"""
|
||||
name = adapter.get_name()
|
||||
if name in self._adapters:
|
||||
@ -121,36 +105,36 @@ class Driver(abc.ABC):
|
||||
|
||||
@abc.abstractmethod
|
||||
def on_startup(self, func: Callable) -> Callable:
|
||||
"""注册一个在驱动启动时运行的函数"""
|
||||
"""注册一个在驱动器启动时执行的函数"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def on_shutdown(self, func: Callable) -> Callable:
|
||||
"""注册一个在驱动停止时运行的函数"""
|
||||
"""注册一个在驱动器停止时执行的函数"""
|
||||
raise NotImplementedError
|
||||
|
||||
def on_bot_connect(self, func: T_BotConnectionHook) -> T_BotConnectionHook:
|
||||
"""
|
||||
装饰一个函数使他在 bot 通过 WebSocket 连接成功时执行。
|
||||
"""装饰一个函数使他在 bot 连接成功时执行。
|
||||
|
||||
参数:
|
||||
bot: 当前连接上的 Bot 对象
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前连接上的 Bot 对象
|
||||
"""
|
||||
self._bot_connection_hook.add(func)
|
||||
return func
|
||||
|
||||
def on_bot_disconnect(self, func: T_BotDisconnectionHook) -> T_BotDisconnectionHook:
|
||||
"""
|
||||
装饰一个函数使他在 bot 通过 WebSocket 连接断开时执行。
|
||||
"""装饰一个函数使他在 bot 连接断开时执行。
|
||||
|
||||
参数:
|
||||
bot: 当前连接上的 Bot 对象
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前连接上的 Bot 对象
|
||||
"""
|
||||
self._bot_disconnection_hook.add(func)
|
||||
return func
|
||||
|
||||
def _bot_connect(self, bot: "Bot") -> None:
|
||||
"""在 WebSocket 连接成功后,调用该函数来注册 bot 对象"""
|
||||
"""在连接成功后,调用该函数来注册 bot 对象"""
|
||||
if bot.self_id in self._clients:
|
||||
raise RuntimeError(f"Duplicate bot connection with id {bot.self_id}")
|
||||
self._clients[bot.self_id] = bot
|
||||
@ -169,7 +153,7 @@ class Driver(abc.ABC):
|
||||
asyncio.create_task(_run_hook(bot))
|
||||
|
||||
def _bot_disconnect(self, bot: "Bot") -> None:
|
||||
"""在 WebSocket 连接断开后,调用该函数来注销 bot 对象"""
|
||||
"""在连接断开后,调用该函数来注销 bot 对象"""
|
||||
if bot.self_id in self._clients:
|
||||
del self._clients[bot.self_id]
|
||||
|
||||
@ -188,32 +172,33 @@ class Driver(abc.ABC):
|
||||
|
||||
|
||||
class ForwardMixin(abc.ABC):
|
||||
"""客户端混入基类。"""
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def type(self) -> str:
|
||||
"""客户端驱动类型名称"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
async def request(self, setup: Request) -> Response:
|
||||
"""发送一个 HTTP 请求"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
@asynccontextmanager
|
||||
async def websocket(self, setup: Request) -> AsyncGenerator[WebSocket, None]:
|
||||
"""发起一个 WebSocket 连接"""
|
||||
raise NotImplementedError
|
||||
yield # used for static type checking's generator detection
|
||||
|
||||
|
||||
class ForwardDriver(Driver, ForwardMixin):
|
||||
"""
|
||||
Forward Driver 基类。将客户端框架封装,以满足适配器使用。
|
||||
"""
|
||||
"""客户端基类。将客户端框架封装,以满足适配器使用。"""
|
||||
|
||||
|
||||
class ReverseDriver(Driver):
|
||||
"""
|
||||
Reverse Driver 基类。将后端框架封装,以满足适配器使用。
|
||||
"""
|
||||
"""服务端基类。将后端框架封装,以满足适配器使用。"""
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
@ -229,20 +214,26 @@ class ReverseDriver(Driver):
|
||||
|
||||
@abc.abstractmethod
|
||||
def setup_http_server(self, setup: "HTTPServerSetup") -> None:
|
||||
"""设置一个 HTTP 服务器路由配置"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def setup_websocket_server(self, setup: "WebSocketServerSetup") -> None:
|
||||
"""设置一个 WebSocket 服务器路由配置"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Driver]:
|
||||
"""将一个驱动器和多个混入类合并。"""
|
||||
# check first
|
||||
assert issubclass(driver, Driver), "`driver` must be subclass of Driver"
|
||||
assert all(
|
||||
map(lambda m: issubclass(m, ForwardMixin), mixins)
|
||||
), "`mixins` must be subclass of ForwardMixin"
|
||||
|
||||
if not mixins:
|
||||
return driver
|
||||
|
||||
class CombinedDriver(*mixins, driver, ForwardDriver): # type: ignore
|
||||
@property
|
||||
def type(self) -> str:
|
||||
@ -257,6 +248,8 @@ def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Dr
|
||||
|
||||
@dataclass
|
||||
class HTTPServerSetup:
|
||||
"""HTTP 服务器路由配置。"""
|
||||
|
||||
path: URL # path should not be absolute, check it by URL.is_absolute() == False
|
||||
method: str
|
||||
name: str
|
||||
@ -265,6 +258,8 @@ class HTTPServerSetup:
|
||||
|
||||
@dataclass
|
||||
class WebSocketServerSetup:
|
||||
"""WebSocket 服务器路由配置。"""
|
||||
|
||||
path: URL # path should not be absolute, check it by URL.is_absolute() == False
|
||||
name: str
|
||||
handle_func: Callable[[WebSocket], Awaitable[Any]]
|
||||
|
@ -1,10 +1,21 @@
|
||||
"""
|
||||
## AIOHTTP 驱动适配
|
||||
"""[AIOHTTP](https://aiohttp.readthedocs.io/en/stable/) 驱动适配器。
|
||||
|
||||
```bash
|
||||
nb driver install aiohttp
|
||||
# 或者
|
||||
pip install nonebot2[aiohttp]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持客户端连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.drivers.aiohttp 模块
|
||||
"""
|
||||
|
||||
from typing import AsyncGenerator
|
||||
from typing import Type, AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from nonebot.typing import overrides
|
||||
@ -12,7 +23,12 @@ from nonebot.drivers import Request, Response
|
||||
from nonebot.exception import WebSocketClosed
|
||||
from nonebot.drivers._block_driver import BlockDriver
|
||||
from nonebot.drivers import WebSocket as BaseWebSocket
|
||||
from nonebot.drivers import HTTPVersion, ForwardMixin, combine_driver
|
||||
from nonebot.drivers import (
|
||||
HTTPVersion,
|
||||
ForwardMixin,
|
||||
ForwardDriver,
|
||||
combine_driver,
|
||||
)
|
||||
|
||||
try:
|
||||
import aiohttp
|
||||
@ -23,6 +39,8 @@ except ImportError:
|
||||
|
||||
|
||||
class Mixin(ForwardMixin):
|
||||
"""AIOHTTP Mixin"""
|
||||
|
||||
@property
|
||||
@overrides(ForwardMixin)
|
||||
def type(self) -> str:
|
||||
@ -84,6 +102,8 @@ class Mixin(ForwardMixin):
|
||||
|
||||
|
||||
class WebSocket(BaseWebSocket):
|
||||
"""AIOHTTP Websocket Wrapper"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@ -138,4 +158,5 @@ class WebSocket(BaseWebSocket):
|
||||
await self.websocket.send_bytes(data)
|
||||
|
||||
|
||||
Driver = combine_driver(BlockDriver, Mixin)
|
||||
Driver: Type[ForwardDriver] = combine_driver(BlockDriver, Mixin) # type: ignore
|
||||
"""AIOHTTP Driver"""
|
||||
|
@ -1,9 +1,12 @@
|
||||
"""
|
||||
## FastAPI 驱动适配
|
||||
"""[FastAPI](https://fastapi.tiangolo.com/) 驱动适配
|
||||
|
||||
本驱动同时支持服务端以及客户端连接
|
||||
:::tip 提示
|
||||
本驱动仅支持服务端连接
|
||||
:::
|
||||
|
||||
后端使用方法请参考: [`FastAPI 文档`](https://fastapi.tiangolo.com/)
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.drivers.fastapi 模块
|
||||
"""
|
||||
|
||||
import logging
|
||||
@ -39,53 +42,33 @@ def catch_closed(func):
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
"""
|
||||
FastAPI 驱动框架设置,详情参考 FastAPI 文档
|
||||
"""
|
||||
"""FastAPI 驱动框架设置,详情参考 FastAPI 文档"""
|
||||
|
||||
fastapi_openapi_url: Optional[str] = None
|
||||
"""
|
||||
`openapi.json` 地址,默认为 `None` 即关闭
|
||||
"""
|
||||
"""`openapi.json` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_docs_url: Optional[str] = None
|
||||
"""
|
||||
`swagger` 地址,默认为 `None` 即关闭
|
||||
"""
|
||||
"""`swagger` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_redoc_url: Optional[str] = None
|
||||
"""
|
||||
`redoc` 地址,默认为 `None` 即关闭
|
||||
"""
|
||||
"""`redoc` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_include_adapter_schema: bool = True
|
||||
"""
|
||||
是否包含适配器路由的 schema,默认为 `True`
|
||||
"""
|
||||
"""是否包含适配器路由的 schema,默认为 `True`"""
|
||||
fastapi_reload: bool = False
|
||||
"""
|
||||
开启/关闭冷重载
|
||||
"""
|
||||
"""开启/关闭冷重载"""
|
||||
fastapi_reload_dirs: Optional[List[str]] = None
|
||||
"""
|
||||
重载监控文件夹列表,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载监控文件夹列表,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_delay: Optional[float] = None
|
||||
"""
|
||||
重载延迟,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载延迟,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_includes: Optional[List[str]] = None
|
||||
"""
|
||||
要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_excludes: Optional[List[str]] = None
|
||||
"""
|
||||
不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
||||
|
||||
|
||||
class Driver(ReverseDriver):
|
||||
"""FastAPI 驱动框架。包含反向 Server 功能。"""
|
||||
"""FastAPI 驱动框架。"""
|
||||
|
||||
def __init__(self, env: Env, config: NoneBotConfig):
|
||||
super(Driver, self).__init__(env, config)
|
||||
@ -254,6 +237,8 @@ class Driver(ReverseDriver):
|
||||
|
||||
|
||||
class FastAPIWebSocket(BaseWebSocket):
|
||||
"""FastAPI WebSocket Wrapper"""
|
||||
|
||||
@overrides(BaseWebSocket)
|
||||
def __init__(self, *, request: BaseRequest, websocket: WebSocket):
|
||||
super().__init__(request=request)
|
||||
@ -294,3 +279,6 @@ class FastAPIWebSocket(BaseWebSocket):
|
||||
@overrides(BaseWebSocket)
|
||||
async def send_bytes(self, data: bytes) -> None:
|
||||
await self.websocket.send({"type": "websocket.send", "bytes": data})
|
||||
|
||||
|
||||
__autodoc__ = {"catch_closed": False}
|
||||
|
@ -1,4 +1,20 @@
|
||||
from typing import AsyncGenerator
|
||||
"""[HTTPX](https://www.python-httpx.org/) 驱动适配
|
||||
|
||||
```bash
|
||||
nb driver install httpx
|
||||
# 或者
|
||||
pip install nonebot2[httpx]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持客户端 HTTP 连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.drivers.httpx 模块
|
||||
"""
|
||||
from typing import Type, AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from nonebot.typing import overrides
|
||||
@ -9,6 +25,7 @@ from nonebot.drivers import (
|
||||
WebSocket,
|
||||
HTTPVersion,
|
||||
ForwardMixin,
|
||||
ForwardDriver,
|
||||
combine_driver,
|
||||
)
|
||||
|
||||
@ -21,6 +38,8 @@ except ImportError:
|
||||
|
||||
|
||||
class Mixin(ForwardMixin):
|
||||
"""HTTPX Mixin"""
|
||||
|
||||
@property
|
||||
@overrides(ForwardMixin)
|
||||
def type(self) -> str:
|
||||
@ -57,4 +76,5 @@ class Mixin(ForwardMixin):
|
||||
yield ws
|
||||
|
||||
|
||||
Driver = combine_driver(BlockDriver, Mixin)
|
||||
Driver: Type[ForwardDriver] = combine_driver(BlockDriver, Mixin) # type: ignore
|
||||
"""HTTPX Driver"""
|
||||
|
@ -1,7 +1,18 @@
|
||||
"""
|
||||
## Quart 驱动适配
|
||||
"""[Quart](https://pgjones.gitlab.io/quart/index.html) 驱动适配
|
||||
|
||||
后端使用方法请参考: [`Quart 文档`](https://pgjones.gitlab.io/quart/index.html)
|
||||
```bash
|
||||
nb driver install quart
|
||||
# 或者
|
||||
pip install nonebot2[quart]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持服务端连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.drivers.quart 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@ -47,39 +58,25 @@ def catch_closed(func):
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
"""
|
||||
Quart 驱动框架设置
|
||||
"""
|
||||
"""Quart 驱动框架设置"""
|
||||
|
||||
quart_reload: bool = False
|
||||
"""
|
||||
开启/关闭冷重载
|
||||
"""
|
||||
"""开启/关闭冷重载"""
|
||||
quart_reload_dirs: Optional[List[str]] = None
|
||||
"""
|
||||
重载监控文件夹列表,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载监控文件夹列表,默认为 uvicorn 默认值"""
|
||||
quart_reload_delay: Optional[float] = None
|
||||
"""
|
||||
重载延迟,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载延迟,默认为 uvicorn 默认值"""
|
||||
quart_reload_includes: Optional[List[str]] = None
|
||||
"""
|
||||
要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
quart_reload_excludes: Optional[List[str]] = None
|
||||
"""
|
||||
不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
||||
|
||||
|
||||
class Driver(ReverseDriver):
|
||||
"""
|
||||
Quart 驱动框架
|
||||
"""
|
||||
"""Quart 驱动框架"""
|
||||
|
||||
def __init__(self, env: Env, config: NoneBotConfig):
|
||||
super().__init__(env, config)
|
||||
@ -239,6 +236,8 @@ class Driver(ReverseDriver):
|
||||
|
||||
|
||||
class WebSocket(BaseWebSocket):
|
||||
"""Quart WebSocket Wrapper"""
|
||||
|
||||
def __init__(self, *, request: BaseRequest, websocket: QuartWebSocket):
|
||||
super().__init__(request=request)
|
||||
self.websocket = websocket
|
||||
@ -280,3 +279,6 @@ class WebSocket(BaseWebSocket):
|
||||
@overrides(BaseWebSocket)
|
||||
async def send_bytes(self, data: bytes):
|
||||
await self.websocket.send(data)
|
||||
|
||||
|
||||
__autodoc__ = {"catch_closed": False}
|
||||
|
@ -1,6 +1,22 @@
|
||||
"""[websockets](https://websockets.readthedocs.io/) 驱动适配
|
||||
|
||||
```bash
|
||||
nb driver install websockets
|
||||
# 或者
|
||||
pip install nonebot2[websockets]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持客户端 WebSocket 连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.drivers.websockets 模块
|
||||
"""
|
||||
import logging
|
||||
from functools import wraps
|
||||
from typing import AsyncGenerator
|
||||
from typing import Type, AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from nonebot.typing import overrides
|
||||
@ -9,7 +25,7 @@ from nonebot.drivers import Request, Response
|
||||
from nonebot.exception import WebSocketClosed
|
||||
from nonebot.drivers._block_driver import BlockDriver
|
||||
from nonebot.drivers import WebSocket as BaseWebSocket
|
||||
from nonebot.drivers import ForwardMixin, combine_driver
|
||||
from nonebot.drivers import ForwardMixin, ForwardDriver, combine_driver
|
||||
|
||||
try:
|
||||
from websockets.exceptions import ConnectionClosed
|
||||
@ -38,6 +54,8 @@ def catch_closed(func):
|
||||
|
||||
|
||||
class Mixin(ForwardMixin):
|
||||
"""Websockets Mixin"""
|
||||
|
||||
@property
|
||||
@overrides(ForwardMixin)
|
||||
def type(self) -> str:
|
||||
@ -60,6 +78,8 @@ class Mixin(ForwardMixin):
|
||||
|
||||
|
||||
class WebSocket(BaseWebSocket):
|
||||
"""Websockets WebSocket Wrapper"""
|
||||
|
||||
@overrides(BaseWebSocket)
|
||||
def __init__(self, *, request: Request, websocket: WebSocketClientProtocol):
|
||||
super().__init__(request=request)
|
||||
@ -103,4 +123,5 @@ class WebSocket(BaseWebSocket):
|
||||
await self.websocket.send(data)
|
||||
|
||||
|
||||
Driver = combine_driver(BlockDriver, Mixin)
|
||||
Driver: Type[ForwardDriver] = combine_driver(BlockDriver, Mixin) # type: ignore
|
||||
"""Websockets Driver"""
|
||||
|
@ -1,8 +1,32 @@
|
||||
"""
|
||||
## 异常
|
||||
"""本模块包含了所有 NoneBot 运行时可能会抛出的异常。
|
||||
|
||||
下列文档中的异常是所有 NoneBot 运行时可能会抛出的。
|
||||
这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。
|
||||
|
||||
```bash
|
||||
NoneBotException
|
||||
├── ParserExit
|
||||
├── ProcessException
|
||||
| ├── IgnoredException
|
||||
| ├── MockApiException
|
||||
| └── StopPropagation
|
||||
├── MatcherException
|
||||
| ├── SkippedException
|
||||
| | └── TypeMisMatch
|
||||
| ├── PausedException
|
||||
| ├── RejectedException
|
||||
| └── FinishedException
|
||||
├── AdapterException
|
||||
| ├── NoLogException
|
||||
| ├── ApiNotAvailable
|
||||
| ├── NetworkError
|
||||
| └── ActionFailed
|
||||
└── DriverException
|
||||
└── WebSocketClosed
|
||||
```
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 10
|
||||
description: nonebot.exception 模块
|
||||
"""
|
||||
|
||||
from typing import Any, Optional
|
||||
@ -11,16 +35,12 @@ from pydantic.fields import ModelField
|
||||
|
||||
|
||||
class NoneBotException(Exception):
|
||||
"""
|
||||
所有 NoneBot 发生的异常基类。
|
||||
"""
|
||||
"""所有 NoneBot 发生的异常基类。"""
|
||||
|
||||
|
||||
# Rule Exception
|
||||
class ParserExit(NoneBotException):
|
||||
"""
|
||||
`shell command` 处理消息失败时返回的异常
|
||||
"""
|
||||
"""{ref}`nonebot.rule.shell_command` 处理消息失败时返回的异常"""
|
||||
|
||||
def __init__(self, status: int = 0, message: Optional[str] = None):
|
||||
self.status = status
|
||||
@ -35,21 +55,18 @@ class ParserExit(NoneBotException):
|
||||
|
||||
# Processor Exception
|
||||
class ProcessException(NoneBotException):
|
||||
"""
|
||||
事件处理过程中发生的异常基类。
|
||||
"""
|
||||
"""事件处理过程中发生的异常基类。"""
|
||||
|
||||
|
||||
class IgnoredException(ProcessException):
|
||||
"""
|
||||
指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。
|
||||
"""指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。
|
||||
|
||||
参数:
|
||||
reason: 忽略事件的原因
|
||||
"""
|
||||
|
||||
def __init__(self, reason):
|
||||
self.reason = reason
|
||||
def __init__(self, reason: Any):
|
||||
self.reason: Any = reason
|
||||
|
||||
def __repr__(self):
|
||||
return f"<IgnoredException, reason={self.reason}>"
|
||||
@ -59,8 +76,7 @@ class IgnoredException(ProcessException):
|
||||
|
||||
|
||||
class MockApiException(ProcessException):
|
||||
"""
|
||||
指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。可由 api hook 抛出。
|
||||
"""指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。可由 api hook 抛出。
|
||||
|
||||
参数:
|
||||
result: 返回的内容
|
||||
@ -77,34 +93,46 @@ class MockApiException(ProcessException):
|
||||
|
||||
|
||||
class StopPropagation(ProcessException):
|
||||
"""
|
||||
指示 NoneBot 终止事件向下层传播。
|
||||
"""指示 NoneBot 终止事件向下层传播。
|
||||
|
||||
在 {ref}`nonebot.matcher.Matcher.block` 为 `True`
|
||||
或使用 {ref}`nonebot.matcher.Matcher.stop_propagation` 方法时抛出。
|
||||
|
||||
用法:
|
||||
在 `Matcher.block == True` 时抛出。
|
||||
```python
|
||||
matcher = on_notice(block=True)
|
||||
# 或者
|
||||
@matcher.handle()
|
||||
async def handler(matcher: Matcher):
|
||||
matcher.stop_propagation()
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
# Matcher Exceptions
|
||||
class MatcherException(NoneBotException):
|
||||
"""
|
||||
所有 Matcher 发生的异常基类。
|
||||
"""
|
||||
"""所有 Matcher 发生的异常基类。"""
|
||||
|
||||
|
||||
class SkippedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 立即结束当前 `Handler` 的处理,继续处理下一个 `Handler`。
|
||||
"""指示 NoneBot 立即结束当前 `Handler` 的处理,继续处理下一个 `Handler`。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.skip` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.skip()` 抛出。
|
||||
```python
|
||||
def always_skip():
|
||||
Matcher.skip()
|
||||
|
||||
@matcher.handle()
|
||||
async def handler(dependency = Depends(always_skip)):
|
||||
...
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class TypeMisMatch(SkippedException):
|
||||
"""
|
||||
当前 `Handler` 的参数类型不匹配。
|
||||
"""
|
||||
"""当前 `Handler` 的参数类型不匹配。"""
|
||||
|
||||
def __init__(self, param: ModelField, value: Any):
|
||||
self.param: ModelField = param
|
||||
@ -118,91 +146,85 @@ class TypeMisMatch(SkippedException):
|
||||
|
||||
|
||||
class PausedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 结束当前 `Handler` 并等待下一条消息后继续下一个 `Handler`。
|
||||
可用于用户输入新信息。
|
||||
"""指示 NoneBot 结束当前 `Handler` 并等待下一条消息后继续下一个 `Handler`。可用于用户输入新信息。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.pause` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.pause()` 抛出。
|
||||
```python
|
||||
@matcher.handle()
|
||||
async def handler():
|
||||
await matcher.pause("some message")
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class RejectedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 结束当前 `Handler` 并等待下一条消息后重新运行当前 `Handler`。
|
||||
可用于用户重新输入。
|
||||
"""指示 NoneBot 结束当前 `Handler` 并等待下一条消息后重新运行当前 `Handler`。可用于用户重新输入。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.reject` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.reject()` 抛出。
|
||||
```python
|
||||
@matcher.handle()
|
||||
async def handler():
|
||||
await matcher.reject("some message")
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class FinishedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 结束当前 `Handler` 且后续 `Handler` 不再被运行。
|
||||
可用于结束用户会话。
|
||||
"""指示 NoneBot 结束当前 `Handler` 且后续 `Handler` 不再被运行。可用于结束用户会话。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.finish` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.finish()` 抛出。
|
||||
```python
|
||||
@matcher.handle()
|
||||
async def handler():
|
||||
await matcher.finish("some message")
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
# Adapter Exceptions
|
||||
class AdapterException(NoneBotException):
|
||||
"""
|
||||
代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception`
|
||||
"""代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception`
|
||||
|
||||
参数:
|
||||
adapter_name: 标识 adapter
|
||||
"""
|
||||
|
||||
def __init__(self, adapter_name: str) -> None:
|
||||
self.adapter_name = adapter_name
|
||||
self.adapter_name: str = adapter_name
|
||||
|
||||
|
||||
class NoLogException(AdapterException):
|
||||
"""
|
||||
指示 NoneBot 对当前 `Event` 进行处理但不显示 Log 信息,可在 `get_log_string` 时抛出
|
||||
"""
|
||||
"""指示 NoneBot 对当前 `Event` 进行处理但不显示 Log 信息。
|
||||
|
||||
pass
|
||||
可在 {ref}`nonebot.adapters._event.Event.get_log_string` 时抛出
|
||||
"""
|
||||
|
||||
|
||||
class ApiNotAvailable(AdapterException):
|
||||
"""
|
||||
在 API 连接不可用时抛出。
|
||||
"""
|
||||
|
||||
pass
|
||||
"""在 API 连接不可用时抛出。"""
|
||||
|
||||
|
||||
class NetworkError(AdapterException):
|
||||
"""
|
||||
在网络出现问题时抛出,如: API 请求地址不正确, API 请求无返回或返回状态非正常等。
|
||||
"""
|
||||
|
||||
pass
|
||||
"""在网络出现问题时抛出,如: API 请求地址不正确, API 请求无返回或返回状态非正常等。"""
|
||||
|
||||
|
||||
class ActionFailed(AdapterException):
|
||||
"""
|
||||
API 请求成功返回数据,但 API 操作失败。
|
||||
"""
|
||||
|
||||
pass
|
||||
"""API 请求成功返回数据,但 API 操作失败。"""
|
||||
|
||||
|
||||
# Driver Exceptions
|
||||
class DriverException(NoneBotException):
|
||||
"""
|
||||
`Driver` 抛出的异常基类
|
||||
"""
|
||||
"""`Driver` 抛出的异常基类"""
|
||||
|
||||
|
||||
class WebSocketClosed(DriverException):
|
||||
"""
|
||||
WebSocket 连接已关闭
|
||||
"""
|
||||
"""WebSocket 连接已关闭"""
|
||||
|
||||
def __init__(self, code: int, reason: Optional[str] = None):
|
||||
self.code = code
|
||||
|
@ -1,11 +1,15 @@
|
||||
"""
|
||||
## 日志
|
||||
"""本模块定义了 NoneBot 的日志记录 Logger。
|
||||
|
||||
NoneBot 使用 [`loguru`][loguru] 来记录日志信息。
|
||||
|
||||
自定义 logger 请参考 [`loguru`][loguru] 文档。
|
||||
自定义 logger 请参考 [自定义日志](https://v2.nonebot.dev/docs/tutorial/custom-logger)
|
||||
以及 [`loguru`][loguru] 文档。
|
||||
|
||||
[loguru]: https://github.com/Delgan/loguru
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 7
|
||||
description: nonebot.log 模块
|
||||
"""
|
||||
|
||||
import sys
|
||||
@ -23,14 +27,13 @@ if TYPE_CHECKING:
|
||||
|
||||
# logger = logging.getLogger("nonebot")
|
||||
logger: "Logger" = loguru.logger
|
||||
"""
|
||||
NoneBot 日志记录器对象。
|
||||
"""NoneBot 日志记录器对象。
|
||||
|
||||
默认信息:
|
||||
|
||||
- 格式: `[%(asctime)s %(name)s] %(levelname)s: %(message)s`
|
||||
- 等级: `INFO` ,根据 `config.log_level` 配置改变
|
||||
- 输出: 输出至 stdout
|
||||
- 格式: `[%(asctime)s %(name)s] %(levelname)s: %(message)s`
|
||||
- 等级: `INFO` ,根据 `config.log_level` 配置改变
|
||||
- 输出: 输出至 stdout
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -80,14 +83,16 @@ class LoguruHandler(logging.Handler): # pragma: no cover
|
||||
|
||||
|
||||
logger.remove()
|
||||
default_filter = Filter()
|
||||
default_format = (
|
||||
default_filter: Filter = Filter()
|
||||
"""默认日志等级过滤器"""
|
||||
default_format: str = (
|
||||
"<g>{time:MM-DD HH:mm:ss}</g> "
|
||||
"[<lvl>{level}</lvl>] "
|
||||
"<c><u>{name}</u></c> | "
|
||||
# "<c>{function}:{line}</c>| "
|
||||
"{message}"
|
||||
)
|
||||
"""默认日志格式"""
|
||||
logger_id = logger.add(
|
||||
sys.stdout,
|
||||
level=0,
|
||||
@ -96,3 +101,5 @@ logger_id = logger.add(
|
||||
filter=default_filter,
|
||||
format=default_format,
|
||||
)
|
||||
|
||||
__autodoc__ = {"Filter": False, "LoguruHandler": False}
|
||||
|
@ -1,7 +1,8 @@
|
||||
"""
|
||||
## 事件响应器
|
||||
"""本模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行对话。
|
||||
|
||||
该模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行对话 。
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.matcher 模块
|
||||
"""
|
||||
|
||||
from types import ModuleType
|
||||
@ -64,9 +65,7 @@ if TYPE_CHECKING:
|
||||
T = TypeVar("T")
|
||||
|
||||
matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
|
||||
"""
|
||||
用于存储当前所有的事件响应器
|
||||
"""
|
||||
"""用于存储当前所有的事件响应器"""
|
||||
current_bot: ContextVar[Bot] = ContextVar("current_bot")
|
||||
current_event: ContextVar[Event] = ContextVar("current_event")
|
||||
current_matcher: ContextVar["Matcher"] = ContextVar("current_matcher")
|
||||
@ -103,68 +102,38 @@ class Matcher(metaclass=MatcherMeta):
|
||||
"""事件响应器类"""
|
||||
|
||||
plugin: Optional["Plugin"] = None
|
||||
"""
|
||||
事件响应器所在插件
|
||||
"""
|
||||
"""事件响应器所在插件"""
|
||||
module: Optional[ModuleType] = None
|
||||
"""
|
||||
事件响应器所在插件模块
|
||||
"""
|
||||
"""事件响应器所在插件模块"""
|
||||
plugin_name: Optional[str] = None
|
||||
"""
|
||||
事件响应器所在插件名
|
||||
"""
|
||||
"""事件响应器所在插件名"""
|
||||
module_name: Optional[str] = None
|
||||
"""
|
||||
事件响应器所在点分割插件模块路径
|
||||
"""
|
||||
"""事件响应器所在点分割插件模块路径"""
|
||||
|
||||
type: str = ""
|
||||
"""
|
||||
事件响应器类型
|
||||
"""
|
||||
"""事件响应器类型"""
|
||||
rule: Rule = Rule()
|
||||
"""
|
||||
事件响应器匹配规则
|
||||
"""
|
||||
"""事件响应器匹配规则"""
|
||||
permission: Permission = Permission()
|
||||
"""
|
||||
事件响应器触发权限
|
||||
"""
|
||||
"""事件响应器触发权限"""
|
||||
handlers: List[Dependent[Any]] = []
|
||||
"""
|
||||
事件响应器拥有的事件处理函数列表
|
||||
"""
|
||||
"""事件响应器拥有的事件处理函数列表"""
|
||||
priority: int = 1
|
||||
"""
|
||||
事件响应器优先级
|
||||
"""
|
||||
"""事件响应器优先级"""
|
||||
block: bool = False
|
||||
"""
|
||||
事件响应器是否阻止事件传播
|
||||
"""
|
||||
"""事件响应器是否阻止事件传播"""
|
||||
temp: bool = False
|
||||
"""
|
||||
事件响应器是否为临时
|
||||
"""
|
||||
"""事件响应器是否为临时"""
|
||||
expire_time: Optional[datetime] = None
|
||||
"""
|
||||
事件响应器过期时间点
|
||||
"""
|
||||
"""事件响应器过期时间点"""
|
||||
|
||||
_default_state: T_State = {}
|
||||
"""
|
||||
事件响应器默认状态
|
||||
"""
|
||||
"""事件响应器默认状态"""
|
||||
|
||||
_default_type_updater: Optional[Dependent[str]] = None
|
||||
"""
|
||||
事件响应器类型更新函数
|
||||
"""
|
||||
"""事件响应器类型更新函数"""
|
||||
_default_permission_updater: Optional[Dependent[Permission]] = None
|
||||
"""
|
||||
事件响应器权限更新函数
|
||||
"""
|
||||
"""事件响应器权限更新函数"""
|
||||
|
||||
HANDLER_PARAM_TYPES = [
|
||||
params.DependParam,
|
||||
@ -177,7 +146,6 @@ class Matcher(metaclass=MatcherMeta):
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
"""实例化 Matcher 以便运行"""
|
||||
self.handlers = self.handlers.copy()
|
||||
self.state = self._default_state.copy()
|
||||
|
||||
@ -272,15 +240,16 @@ class Matcher(metaclass=MatcherMeta):
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否满足触发权限
|
||||
"""检查是否满足触发权限
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
event: 上报事件
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
|
||||
返回:
|
||||
bool: 是否满足权限
|
||||
是否满足权限
|
||||
"""
|
||||
event_type = event.get_type()
|
||||
return event_type == (cls.type or event_type) and await cls.permission(
|
||||
@ -296,16 +265,17 @@ class Matcher(metaclass=MatcherMeta):
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否满足匹配规则
|
||||
"""检查是否满足匹配规则
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
event: 上报事件
|
||||
state: 当前状态
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
|
||||
返回:
|
||||
bool: 是否满足匹配规则
|
||||
是否满足匹配规则
|
||||
"""
|
||||
event_type = event.get_type()
|
||||
return event_type == (cls.type or event_type) and await cls.rule(
|
||||
@ -314,8 +284,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def type_updater(cls, func: T_TypeUpdater) -> T_TypeUpdater:
|
||||
"""
|
||||
装饰一个函数来更改当前事件响应器的默认响应事件类型更新函数
|
||||
"""装饰一个函数来更改当前事件响应器的默认响应事件类型更新函数
|
||||
|
||||
参数:
|
||||
func: 响应事件类型更新函数
|
||||
@ -327,8 +296,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def permission_updater(cls, func: T_PermissionUpdater) -> T_PermissionUpdater:
|
||||
"""
|
||||
装饰一个函数来更改当前事件响应器的默认会话权限更新函数
|
||||
"""装饰一个函数来更改当前事件响应器的默认会话权限更新函数
|
||||
|
||||
参数:
|
||||
func: 会话权限更新函数
|
||||
@ -354,8 +322,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
def handle(
|
||||
cls, parameterless: Optional[List[Any]] = None
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""
|
||||
装饰一个函数来向事件响应器直接添加一个处理函数
|
||||
"""装饰一个函数来向事件响应器直接添加一个处理函数
|
||||
|
||||
参数:
|
||||
parameterless: 非参数类型依赖列表
|
||||
@ -371,8 +338,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
def receive(
|
||||
cls, id: str = "", parameterless: Optional[List[Any]] = None
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""
|
||||
装饰一个函数来指示 NoneBot 在接收用户新的一条消息后继续运行该函数
|
||||
"""装饰一个函数来指示 NoneBot 在接收用户新的一条消息后继续运行该函数
|
||||
|
||||
参数:
|
||||
id: 消息 ID
|
||||
@ -410,8 +376,9 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
parameterless: Optional[List[Any]] = None,
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""
|
||||
装饰一个函数来指示 NoneBot 当要获取的 `key` 不存在时接收用户新的一条消息再运行该函数,如果 `key` 已存在则直接继续运行
|
||||
"""装饰一个函数来指示 NoneBot 获取一个参数 `key`
|
||||
|
||||
当要获取的 `key` 不存在时接收用户新的一条消息再运行该函数,如果 `key` 已存在则直接继续运行
|
||||
|
||||
参数:
|
||||
key: 参数名
|
||||
@ -452,12 +419,11 @@ class Matcher(metaclass=MatcherMeta):
|
||||
message: Union[str, Message, MessageSegment, MessageTemplate],
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""
|
||||
发送一条消息给当前交互用户
|
||||
"""发送一条消息给当前交互用户
|
||||
|
||||
参数:
|
||||
message: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
bot = current_bot.get()
|
||||
event = current_event.get()
|
||||
@ -474,12 +440,11 @@ class Matcher(metaclass=MatcherMeta):
|
||||
message: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
发送一条消息给当前交互用户并结束当前事件响应器
|
||||
"""发送一条消息给当前交互用户并结束当前事件响应器
|
||||
|
||||
参数:
|
||||
message: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
if message is not None:
|
||||
await cls.send(message, **kwargs)
|
||||
@ -491,12 +456,11 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续下一个处理函数
|
||||
"""发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续下一个处理函数
|
||||
|
||||
参数:
|
||||
prompt: 消息内容
|
||||
**kwargs`: bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
if prompt is not None:
|
||||
await cls.send(prompt, **kwargs)
|
||||
@ -508,12 +472,12 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
最近使用 `got` / `receive` 接收的消息不符合预期,发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
"""最近使用 `got` / `receive` 接收的消息不符合预期,
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
|
||||
参数:
|
||||
prompt: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
if prompt is not None:
|
||||
await cls.send(prompt, **kwargs)
|
||||
@ -526,13 +490,13 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
最近使用 `got` 接收的消息不符合预期,发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
"""最近使用 `got` 接收的消息不符合预期,
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
|
||||
参数:
|
||||
key: 参数名
|
||||
prompt: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
matcher = current_matcher.get()
|
||||
matcher.set_target(ARG_KEY.format(key=key))
|
||||
@ -547,13 +511,13 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
最近使用 `got` 接收的消息不符合预期,发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
"""最近使用 `got` 接收的消息不符合预期,
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
|
||||
参数:
|
||||
id: 消息 id
|
||||
prompt: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
matcher = current_matcher.get()
|
||||
matcher.set_target(RECEIVE_KEY.format(id=id))
|
||||
@ -563,22 +527,40 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def skip(cls) -> NoReturn:
|
||||
"""跳过当前事件处理函数,继续下一个处理函数
|
||||
|
||||
通常在事件处理函数的依赖中使用。
|
||||
"""
|
||||
raise SkippedException
|
||||
|
||||
def get_receive(self, id: str, default: T = None) -> Union[Event, T]:
|
||||
"""获取一个 `receive` 事件
|
||||
|
||||
如果没有找到对应的事件,返回 `default` 值
|
||||
"""
|
||||
return self.state.get(RECEIVE_KEY.format(id=id), default)
|
||||
|
||||
def set_receive(self, id: str, event: Event) -> None:
|
||||
"""设置一个 `receive` 事件"""
|
||||
self.state[RECEIVE_KEY.format(id=id)] = event
|
||||
self.state[LAST_RECEIVE_KEY] = event
|
||||
|
||||
def get_last_receive(self, default: T = None) -> Union[Event, T]:
|
||||
"""获取最近一次 `receive` 事件
|
||||
|
||||
如果没有事件,返回 `default` 值
|
||||
"""
|
||||
return self.state.get(LAST_RECEIVE_KEY, default)
|
||||
|
||||
def get_arg(self, key: str, default: T = None) -> Union[Message, T]:
|
||||
"""获取一个 `got` 消息
|
||||
|
||||
如果没有找到对应的消息,返回 `default` 值
|
||||
"""
|
||||
return self.state.get(ARG_KEY.format(key=key), default)
|
||||
|
||||
def set_arg(self, key: str, message: Message) -> None:
|
||||
"""设置一个 `got` 消息"""
|
||||
self.state[ARG_KEY.format(key=key)] = message
|
||||
|
||||
def set_target(self, target: str, cache: bool = True) -> None:
|
||||
@ -591,9 +573,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
return self.state.get(REJECT_TARGET, default)
|
||||
|
||||
def stop_propagation(self):
|
||||
"""
|
||||
阻止事件传播
|
||||
"""
|
||||
"""阻止事件传播"""
|
||||
self.block = True
|
||||
|
||||
async def update_type(self, bot: Bot, event: Event) -> str:
|
||||
@ -714,3 +694,14 @@ class Matcher(metaclass=MatcherMeta):
|
||||
)
|
||||
except FinishedException:
|
||||
pass
|
||||
|
||||
|
||||
__autodoc__ = {
|
||||
"MatcherMeta": False,
|
||||
"Matcher.get_target": False,
|
||||
"Matcher.set_target": False,
|
||||
"Matcher.update_type": False,
|
||||
"Matcher.update_permission": False,
|
||||
"Matcher.resolve_reject": False,
|
||||
"Matcher.simple_run": False,
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""
|
||||
## 事件处理
|
||||
"""本模块定义了事件处理主要流程。
|
||||
|
||||
NoneBot 内部处理并按优先级分发事件给所有事件响应器,提供了多个插槽以进行事件的预处理等。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.message 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@ -67,9 +70,7 @@ RUN_POSTPCS_PARAMS = [
|
||||
|
||||
|
||||
def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
||||
"""
|
||||
事件预处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。
|
||||
"""
|
||||
"""事件预处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。"""
|
||||
_event_preprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=EVENT_PCS_PARAMS)
|
||||
)
|
||||
@ -77,9 +78,7 @@ def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
||||
|
||||
|
||||
def event_postprocessor(func: T_EventPostProcessor) -> T_EventPostProcessor:
|
||||
"""
|
||||
事件后处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。
|
||||
"""
|
||||
"""事件后处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。"""
|
||||
_event_postprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=EVENT_PCS_PARAMS)
|
||||
)
|
||||
@ -87,9 +86,7 @@ def event_postprocessor(func: T_EventPostProcessor) -> T_EventPostProcessor:
|
||||
|
||||
|
||||
def run_preprocessor(func: T_RunPreProcessor) -> T_RunPreProcessor:
|
||||
"""
|
||||
运行预处理。装饰一个函数,使它在每次事件响应器运行前执行。
|
||||
"""
|
||||
"""运行预处理。装饰一个函数,使它在每次事件响应器运行前执行。"""
|
||||
_run_preprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=RUN_PREPCS_PARAMS)
|
||||
)
|
||||
@ -97,9 +94,7 @@ def run_preprocessor(func: T_RunPreProcessor) -> T_RunPreProcessor:
|
||||
|
||||
|
||||
def run_postprocessor(func: T_RunPostProcessor) -> T_RunPostProcessor:
|
||||
"""
|
||||
运行后处理。装饰一个函数,使它在每次事件响应器运行后执行。
|
||||
"""
|
||||
"""运行后处理。装饰一个函数,使它在每次事件响应器运行后执行。"""
|
||||
_run_postprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=RUN_POSTPCS_PARAMS)
|
||||
)
|
||||
@ -232,8 +227,7 @@ async def _run_matcher(
|
||||
|
||||
|
||||
async def handle_event(bot: "Bot", event: "Event") -> None:
|
||||
"""
|
||||
处理一个事件。调用该函数以实现分发事件。
|
||||
"""处理一个事件。调用该函数以实现分发事件。
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
|
@ -1,3 +1,10 @@
|
||||
"""本模块定义了依赖注入的各类参数。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.params 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import inspect
|
||||
import warnings
|
||||
@ -55,8 +62,7 @@ def Depends(
|
||||
*,
|
||||
use_cache: bool = True,
|
||||
) -> Any:
|
||||
"""
|
||||
参数依赖注入装饰器
|
||||
"""子依赖装饰器
|
||||
|
||||
参数:
|
||||
dependency: 依赖函数。默认为参数的类型注释。
|
||||
@ -81,6 +87,8 @@ def Depends(
|
||||
|
||||
|
||||
class DependParam(Param):
|
||||
"""子依赖参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls,
|
||||
@ -176,6 +184,8 @@ class _BotChecker(Param):
|
||||
|
||||
|
||||
class BotParam(Param):
|
||||
"""{ref}`nonebot.adapters._bot.Bot` 参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -217,6 +227,8 @@ class _EventChecker(Param):
|
||||
|
||||
|
||||
class EventParam(Param):
|
||||
"""{ref}`nonebot.adapters._event.Event` 参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -250,6 +262,7 @@ async def _event_type(event: Event) -> str:
|
||||
|
||||
|
||||
def EventType() -> str:
|
||||
"""{ref}`nonebot.adapters._event.Event` 类型参数"""
|
||||
return Depends(_event_type)
|
||||
|
||||
|
||||
@ -258,6 +271,7 @@ async def _event_message(event: Event) -> Message:
|
||||
|
||||
|
||||
def EventMessage() -> Any:
|
||||
"""{ref}`nonebot.adapters._event.Event` 消息参数"""
|
||||
return Depends(_event_message)
|
||||
|
||||
|
||||
@ -266,6 +280,7 @@ async def _event_plain_text(event: Event) -> str:
|
||||
|
||||
|
||||
def EventPlainText() -> str:
|
||||
"""{ref}`nonebot.adapters._event.Event` 纯文本消息参数"""
|
||||
return Depends(_event_plain_text)
|
||||
|
||||
|
||||
@ -274,6 +289,7 @@ async def _event_to_me(event: Event) -> bool:
|
||||
|
||||
|
||||
def EventToMe() -> bool:
|
||||
"""{ref}`nonebot.adapters._event.Event` `to_me` 参数"""
|
||||
return Depends(_event_to_me)
|
||||
|
||||
|
||||
@ -282,11 +298,14 @@ class StateInner(T_State):
|
||||
|
||||
|
||||
def State() -> T_State:
|
||||
warnings.warn("State() is deprecated, use T_State instead", DeprecationWarning)
|
||||
"""**Deprecated**: 事件处理状态参数,请直接使用 {ref}`nonebot.typing.T_State`"""
|
||||
warnings.warn("State() is deprecated, use `T_State` instead", DeprecationWarning)
|
||||
return StateInner()
|
||||
|
||||
|
||||
class StateParam(Param):
|
||||
"""事件处理状态参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -308,7 +327,8 @@ def _command(state: T_State) -> Message:
|
||||
|
||||
|
||||
def Command() -> Tuple[str, ...]:
|
||||
return Depends(_command, use_cache=False)
|
||||
"""消息命令元组"""
|
||||
return Depends(_command)
|
||||
|
||||
|
||||
def _raw_command(state: T_State) -> Message:
|
||||
@ -316,7 +336,8 @@ def _raw_command(state: T_State) -> Message:
|
||||
|
||||
|
||||
def RawCommand() -> str:
|
||||
return Depends(_raw_command, use_cache=False)
|
||||
"""消息命令文本"""
|
||||
return Depends(_raw_command)
|
||||
|
||||
|
||||
def _command_arg(state: T_State) -> Message:
|
||||
@ -324,7 +345,8 @@ def _command_arg(state: T_State) -> Message:
|
||||
|
||||
|
||||
def CommandArg() -> Any:
|
||||
return Depends(_command_arg, use_cache=False)
|
||||
"""消息命令参数"""
|
||||
return Depends(_command_arg)
|
||||
|
||||
|
||||
def _shell_command_args(state: T_State) -> Any:
|
||||
@ -332,6 +354,7 @@ def _shell_command_args(state: T_State) -> Any:
|
||||
|
||||
|
||||
def ShellCommandArgs():
|
||||
"""shell 命令解析后的参数字典"""
|
||||
return Depends(_shell_command_args, use_cache=False)
|
||||
|
||||
|
||||
@ -340,6 +363,7 @@ def _shell_command_argv(state: T_State) -> List[str]:
|
||||
|
||||
|
||||
def ShellCommandArgv() -> Any:
|
||||
"""shell 命令原始参数列表"""
|
||||
return Depends(_shell_command_argv, use_cache=False)
|
||||
|
||||
|
||||
@ -348,6 +372,7 @@ def _regex_matched(state: T_State) -> str:
|
||||
|
||||
|
||||
def RegexMatched() -> str:
|
||||
"""正则匹配结果"""
|
||||
return Depends(_regex_matched, use_cache=False)
|
||||
|
||||
|
||||
@ -356,6 +381,7 @@ def _regex_group(state: T_State):
|
||||
|
||||
|
||||
def RegexGroup() -> Tuple[Any, ...]:
|
||||
"""正则匹配结果 group 元组"""
|
||||
return Depends(_regex_group, use_cache=False)
|
||||
|
||||
|
||||
@ -364,10 +390,13 @@ def _regex_dict(state: T_State):
|
||||
|
||||
|
||||
def RegexDict() -> Dict[str, Any]:
|
||||
"""正则匹配结果 group 字典"""
|
||||
return Depends(_regex_dict, use_cache=False)
|
||||
|
||||
|
||||
class MatcherParam(Param):
|
||||
"""事件响应器实例参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -382,6 +411,8 @@ class MatcherParam(Param):
|
||||
|
||||
|
||||
def Received(id: Optional[str] = None, default: Any = None) -> Any:
|
||||
"""`receive` 事件参数"""
|
||||
|
||||
def _received(matcher: "Matcher"):
|
||||
return matcher.get_receive(id or "", default)
|
||||
|
||||
@ -389,6 +420,8 @@ def Received(id: Optional[str] = None, default: Any = None) -> Any:
|
||||
|
||||
|
||||
def LastReceived(default: Any = None) -> Any:
|
||||
"""`last_receive` 事件参数"""
|
||||
|
||||
def _last_received(matcher: "Matcher") -> Any:
|
||||
return matcher.get_last_receive(default)
|
||||
|
||||
@ -404,18 +437,23 @@ class ArgInner:
|
||||
|
||||
|
||||
def Arg(key: Optional[str] = None) -> Any:
|
||||
"""`got` 的 Arg 参数消息"""
|
||||
return ArgInner(key, "message")
|
||||
|
||||
|
||||
def ArgStr(key: Optional[str] = None) -> str:
|
||||
"""`got` 的 Arg 参数消息文本"""
|
||||
return ArgInner(key, "str") # type: ignore
|
||||
|
||||
|
||||
def ArgPlainText(key: Optional[str] = None) -> str:
|
||||
"""`got` 的 Arg 参数消息纯文本"""
|
||||
return ArgInner(key, "plaintext") # type: ignore
|
||||
|
||||
|
||||
class ArgParam(Param):
|
||||
"""`got` 的 Arg 参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -436,6 +474,8 @@ class ArgParam(Param):
|
||||
|
||||
|
||||
class ExceptionParam(Param):
|
||||
"""`run_postprocessor` 的异常参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -450,6 +490,8 @@ class ExceptionParam(Param):
|
||||
|
||||
|
||||
class DefaultParam(Param):
|
||||
"""默认值参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -462,3 +504,9 @@ class DefaultParam(Param):
|
||||
|
||||
|
||||
from nonebot.matcher import Matcher
|
||||
|
||||
__autodoc__ = {
|
||||
"DependsInner": False,
|
||||
"StateInner": False,
|
||||
"ArgInner": False,
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
"""
|
||||
## 权限
|
||||
"""本模块是 {ref}`nonebot.matcher.Matcher.permission` 的类型定义。
|
||||
|
||||
每个 `Matcher` 拥有一个 `Permission` ,其中是 `PermissionChecker` 的集合,只要有一个 `PermissionChecker` 检查结果为 `True` 时就会继续运行。
|
||||
每个 {ref}`nonebot.matcher.Matcher` 拥有一个 {ref}`nonebot.permission.Permission` ,
|
||||
其中是 `PermissionChecker` 的集合,只要有一个 `PermissionChecker` 检查结果为 `True` 时就会继续运行。
|
||||
|
||||
::: tip 提示
|
||||
`PermissionChecker` 既可以是 async function 也可以是 sync function
|
||||
:::
|
||||
FrontMatter:
|
||||
sidebar_position: 6
|
||||
description: nonebot.permission 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@ -15,7 +15,7 @@ from typing import Any, Set, Tuple, Union, NoReturn, Optional, Coroutine
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.dependencies import Dependent
|
||||
from nonebot.exception import SkippedException
|
||||
from nonebot.typing import T_Handler, T_DependencyCache, T_PermissionChecker
|
||||
from nonebot.typing import T_DependencyCache, T_PermissionChecker
|
||||
from nonebot.params import (
|
||||
BotParam,
|
||||
EventType,
|
||||
@ -33,15 +33,18 @@ async def _run_coro_with_catch(coro: Coroutine[Any, Any, Any]):
|
||||
|
||||
|
||||
class Permission:
|
||||
"""
|
||||
`Matcher` 规则类,当事件传递时,在 `Matcher` 运行前进行检查。
|
||||
"""{ref}`nonebot.matcher.Matcher` 权限类。
|
||||
|
||||
当事件传递时,在 {ref}`nonebot.matcher.Matcher` 运行前进行检查。
|
||||
|
||||
参数:
|
||||
checkers: PermissionChecker
|
||||
|
||||
用法:
|
||||
```python
|
||||
Permission(async_function) | sync_function
|
||||
# 等价于
|
||||
from nonebot.utils import run_sync
|
||||
Permission(async_function, run_sync(sync_function))
|
||||
Permission(async_function, sync_function)
|
||||
```
|
||||
"""
|
||||
|
||||
@ -55,11 +58,6 @@ class Permission:
|
||||
]
|
||||
|
||||
def __init__(self, *checkers: Union[T_PermissionChecker, Dependent[bool]]) -> None:
|
||||
"""
|
||||
参数:
|
||||
*checkers: PermissionChecker
|
||||
"""
|
||||
|
||||
self.checkers: Set[Dependent[bool]] = set(
|
||||
checker
|
||||
if isinstance(checker, Dependent)
|
||||
@ -68,9 +66,7 @@ class Permission:
|
||||
)
|
||||
for checker in checkers
|
||||
)
|
||||
"""
|
||||
存储 `PermissionChecker`
|
||||
"""
|
||||
"""存储 `PermissionChecker`"""
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
@ -79,8 +75,7 @@ class Permission:
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否满足某个权限
|
||||
"""检查是否满足某个权限
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
@ -120,44 +115,73 @@ class Permission:
|
||||
|
||||
|
||||
class Message:
|
||||
"""检查是否为消息事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "message"
|
||||
|
||||
|
||||
class Notice:
|
||||
"""检查是否为通知事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "notice"
|
||||
|
||||
|
||||
class Request:
|
||||
"""检查是否为请求事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "request"
|
||||
|
||||
|
||||
class MetaEvent:
|
||||
"""检查是否为元事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "meta_event"
|
||||
|
||||
|
||||
MESSAGE = Permission(Message())
|
||||
MESSAGE: Permission = Permission(Message())
|
||||
"""匹配任意 `message` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 message type 的 Matcher。
|
||||
"""
|
||||
匹配任意 `message` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 message type 的 Matcher。
|
||||
NOTICE: Permission = Permission(Notice())
|
||||
"""匹配任意 `notice` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 notice type 的 Matcher。
|
||||
"""
|
||||
NOTICE = Permission(Notice())
|
||||
REQUEST: Permission = Permission(Request())
|
||||
"""匹配任意 `request` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 request type 的 Matcher。
|
||||
"""
|
||||
匹配任意 `notice` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 notice type 的 Matcher。
|
||||
"""
|
||||
REQUEST = Permission(Request())
|
||||
"""
|
||||
匹配任意 `request` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 request type 的 Matcher。
|
||||
"""
|
||||
METAEVENT = Permission(MetaEvent())
|
||||
"""
|
||||
匹配任意 `meta_event` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 meta_event type 的 Matcher。
|
||||
METAEVENT: Permission = Permission(MetaEvent())
|
||||
"""匹配任意 `meta_event` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 meta_event type 的 Matcher。
|
||||
"""
|
||||
|
||||
|
||||
class User:
|
||||
"""检查当前事件是否属于指定会话
|
||||
|
||||
参数:
|
||||
users: 会话 ID 元组
|
||||
perm: 需同时满足的权限
|
||||
"""
|
||||
|
||||
__slots__ = ("users", "perm")
|
||||
|
||||
def __init__(
|
||||
self, users: Tuple[str, ...], perm: Optional[Permission] = None
|
||||
) -> None:
|
||||
@ -172,18 +196,21 @@ class User:
|
||||
|
||||
|
||||
def USER(*users: str, perm: Optional[Permission] = None):
|
||||
"""
|
||||
`event` 的 `session_id` 在白名单内且满足 perm
|
||||
"""匹配当前事件属于指定会话
|
||||
|
||||
参数:
|
||||
*user: 白名单
|
||||
perm: 需要同时满足的权限
|
||||
user: 会话白名单
|
||||
perm: 需要同时满足的权限
|
||||
"""
|
||||
|
||||
return Permission(User(users, perm))
|
||||
|
||||
|
||||
class SuperUser:
|
||||
"""检查当前事件是否是消息事件且属于超级管理员"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, bot: Bot, event: Event) -> bool:
|
||||
return event.get_type() == "message" and (
|
||||
f"{bot.adapter.get_name().split(maxsplit=1)[0].lower()}:{event.get_user_id()}"
|
||||
@ -192,7 +219,7 @@ class SuperUser:
|
||||
)
|
||||
|
||||
|
||||
SUPERUSER = Permission(SuperUser())
|
||||
"""
|
||||
匹配任意超级用户消息类型事件
|
||||
"""
|
||||
SUPERUSER: Permission = Permission(SuperUser())
|
||||
"""匹配任意超级用户消息类型事件"""
|
||||
|
||||
__autodoc__ = {"Permission.__call__": True}
|
||||
|
@ -1,7 +1,37 @@
|
||||
"""
|
||||
## 插件
|
||||
"""本模块为 NoneBot 插件开发提供便携的定义函数。
|
||||
|
||||
为 NoneBot 插件开发提供便携的定义函数。
|
||||
## 快捷导入
|
||||
|
||||
为方便使用,本模块从子模块导入了部分内容,以下内容可以直接通过本模块导入:
|
||||
|
||||
- `on` => {ref}``on` <nonebot.plugin.on.on>`
|
||||
- `on_metaevent` => {ref}``on_metaevent` <nonebot.plugin.on.on_metaevent>`
|
||||
- `on_message` => {ref}``on_message` <nonebot.plugin.on.on_message>`
|
||||
- `on_notice` => {ref}``on_notice` <nonebot.plugin.on.on_notice>`
|
||||
- `on_request` => {ref}``on_request` <nonebot.plugin.on.on_request>`
|
||||
- `on_startswith` => {ref}``on_startswith` <nonebot.plugin.on.on_startswith>`
|
||||
- `on_endswith` => {ref}``on_endswith` <nonebot.plugin.on.on_endswith>`
|
||||
- `on_keyword` => {ref}``on_keyword` <nonebot.plugin.on.on_keyword>`
|
||||
- `on_command` => {ref}``on_command` <nonebot.plugin.on.on_command>`
|
||||
- `on_shell_command` => {ref}``on_shell_command` <nonebot.plugin.on.on_shell_command>`
|
||||
- `on_regex` => {ref}``on_regex` <nonebot.plugin.on.on_regex>`
|
||||
- `CommandGroup` => {ref}``CommandGroup` <nonebot.plugin.on.CommandGroup>`
|
||||
- `Matchergroup` => {ref}``MatcherGroup` <nonebot.plugin.on.MatcherGroup>`
|
||||
- `load_plugin` => {ref}``load_plugin` <nonebot.plugin.load.load_plugin>`
|
||||
- `load_plugins` => {ref}``load_plugins` <nonebot.plugin.load.load_plugins>`
|
||||
- `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>`
|
||||
- `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>`
|
||||
- `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>`
|
||||
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
|
||||
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>`
|
||||
- `get_plugin` => {ref}``get_plugin` <nonebot.plugin.plugin.get_plugin>`
|
||||
- `get_loaded_plugins` => {ref}``get_loaded_plugins` <nonebot.plugin.plugin.get_loaded_plugins>`
|
||||
- `export` => {ref}``export` <nonebot.plugin.export.export>`
|
||||
- `require` => {ref}``require` <nonebot.plugin.load.require>`
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.plugin 模块
|
||||
"""
|
||||
|
||||
from typing import List, Optional
|
||||
|
@ -1,9 +1,17 @@
|
||||
"""本模块定义了插件导出的内容对象。
|
||||
|
||||
在新版插件系统中,推荐优先使用直接 import 所需要的插件内容。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.plugin.export 模块
|
||||
"""
|
||||
|
||||
from . import _current_plugin
|
||||
|
||||
|
||||
class Export(dict):
|
||||
"""
|
||||
插件导出内容以使得其他插件可以获得。
|
||||
"""插件导出内容以使得其他插件可以获得。
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -42,9 +50,7 @@ class Export(dict):
|
||||
|
||||
|
||||
def export() -> Export:
|
||||
"""
|
||||
获取插件的导出内容对象
|
||||
"""
|
||||
"""获取当前插件的导出内容对象"""
|
||||
plugin = _current_plugin.get()
|
||||
if not plugin:
|
||||
raise RuntimeError("Export outside of the plugin!")
|
||||
|
@ -1,3 +1,9 @@
|
||||
"""本模块定义插件加载接口。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.plugin.load 模块
|
||||
"""
|
||||
import json
|
||||
import warnings
|
||||
from typing import Set, Iterable, Optional
|
||||
@ -11,8 +17,7 @@ from .plugin import Plugin, get_plugin
|
||||
|
||||
|
||||
def load_plugin(module_path: str) -> Optional[Plugin]:
|
||||
"""
|
||||
使用 `PluginManager` 加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
|
||||
"""加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
|
||||
|
||||
参数:
|
||||
module_path: 插件名称 `path.to.your.plugin`
|
||||
@ -24,11 +29,10 @@ def load_plugin(module_path: str) -> Optional[Plugin]:
|
||||
|
||||
|
||||
def load_plugins(*plugin_dir: str) -> Set[Plugin]:
|
||||
"""
|
||||
导入目录下多个插件,以 `_` 开头的插件不会被导入!
|
||||
"""导入文件夹下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
plugin_dir: 插件路径
|
||||
plugin_dir: 文件夹路径
|
||||
"""
|
||||
manager = PluginManager(search_path=plugin_dir)
|
||||
_managers.append(manager)
|
||||
@ -38,12 +42,11 @@ def load_plugins(*plugin_dir: str) -> Set[Plugin]:
|
||||
def load_all_plugins(
|
||||
module_path: Iterable[str], plugin_dir: Iterable[str]
|
||||
) -> Set[Plugin]:
|
||||
"""
|
||||
导入指定列表中的插件以及指定目录下多个插件,以 `_` 开头的插件不会被导入!
|
||||
"""导入指定列表中的插件以及指定目录下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
module_path: 指定插件集合
|
||||
plugin_dir: 指定插件路径集合
|
||||
plugin_dir: 指定文件夹路径集合
|
||||
"""
|
||||
manager = PluginManager(module_path, plugin_dir)
|
||||
_managers.append(manager)
|
||||
@ -51,12 +54,23 @@ def load_all_plugins(
|
||||
|
||||
|
||||
def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
"""
|
||||
导入指定 json 文件中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入!
|
||||
"""导入指定 json 文件中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
file_path: 指定 json 文件路径
|
||||
encoding: 指定 json 文件编码
|
||||
|
||||
用法:
|
||||
```json title=plugins.json
|
||||
{
|
||||
"plugins": ["some_plugin"],
|
||||
"plugin_dirs": ["some_dir"]
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
nonebot.load_from_json("plugins.json")
|
||||
```
|
||||
"""
|
||||
with open(file_path, "r", encoding=encoding) as f:
|
||||
data = json.load(f)
|
||||
@ -68,13 +82,22 @@ def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
|
||||
|
||||
def load_from_toml(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
"""
|
||||
导入指定 toml 文件 `[tool.nonebot]` 中的 `plugins` 以及 `plugin_dirs` 下多个插件,
|
||||
以 `_` 开头的插件不会被导入!
|
||||
"""导入指定 toml 文件 `[tool.nonebot]` 中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
file_path: 指定 toml 文件路径
|
||||
encoding: 指定 toml 文件编码
|
||||
|
||||
用法:
|
||||
```toml title=pyproject.toml
|
||||
[tool.nonebot]
|
||||
plugins = ["some_plugin"]
|
||||
plugin_dirs = ["some_dir"]
|
||||
```
|
||||
|
||||
```python
|
||||
nonebot.load_from_toml("pyproject.toml")
|
||||
```
|
||||
"""
|
||||
with open(file_path, "r", encoding=encoding) as f:
|
||||
data = tomlkit.parse(f.read()) # type: ignore
|
||||
@ -97,25 +120,30 @@ def load_from_toml(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
|
||||
|
||||
def load_builtin_plugin(name: str) -> Optional[Plugin]:
|
||||
"""
|
||||
导入 NoneBot 内置插件
|
||||
"""导入 NoneBot 内置插件。
|
||||
|
||||
参数:
|
||||
name: 插件名称
|
||||
"""
|
||||
return load_plugin(f"nonebot.plugins.{name}")
|
||||
|
||||
|
||||
def load_builtin_plugins(*plugins) -> Set[Plugin]:
|
||||
"""
|
||||
导入多个 NoneBot 内置插件
|
||||
"""导入多个 NoneBot 内置插件。
|
||||
|
||||
参数:
|
||||
plugins: 插件名称列表
|
||||
"""
|
||||
return load_all_plugins([f"nonebot.plugins.{p}" for p in plugins], [])
|
||||
|
||||
|
||||
def require(name: str) -> Export:
|
||||
"""
|
||||
获取一个插件的导出内容
|
||||
"""获取一个插件的导出内容。
|
||||
|
||||
如果为 `load_plugins` 文件夹导入的插件,则为文件(夹)名。
|
||||
|
||||
参数:
|
||||
name: 插件名,与 `load_plugin` 参数一致。如果为 `load_plugins` 导入的插件,则为文件(夹)名。
|
||||
name: 插件名,即 {ref}`nonebot.plugin.plugin.Plugin.name`。
|
||||
|
||||
异常:
|
||||
RuntimeError: 插件无法加载
|
||||
|
@ -1,3 +1,11 @@
|
||||
"""本模块实现插件加载流程。
|
||||
|
||||
参考: [import hooks](https://docs.python.org/3/reference/import.html#import-hooks), [PEP302](https://www.python.org/dev/peps/pep-0302/)
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.plugin.manager 模块
|
||||
"""
|
||||
import sys
|
||||
import pkgutil
|
||||
import importlib
|
||||
|
@ -1,3 +1,9 @@
|
||||
"""本模块定义事件响应器便携定义函数。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.plugin.on 模块
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import inspect
|
||||
|
@ -1,3 +1,9 @@
|
||||
"""本模块定义插件对象。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.plugin.plugin 模块
|
||||
"""
|
||||
from types import ModuleType
|
||||
from dataclasses import field, dataclass
|
||||
from typing import TYPE_CHECKING, Set, Dict, Type, Optional
|
||||
@ -10,9 +16,7 @@ if TYPE_CHECKING:
|
||||
from .manager import PluginManager
|
||||
|
||||
plugins: Dict[str, "Plugin"] = {}
|
||||
"""
|
||||
已加载的插件
|
||||
"""
|
||||
"""已加载的插件"""
|
||||
|
||||
|
||||
@dataclass(eq=False)
|
||||
@ -20,53 +24,36 @@ class Plugin(object):
|
||||
"""存储插件信息"""
|
||||
|
||||
name: str
|
||||
"""
|
||||
插件名称,使用 文件/文件夹 名称作为插件名
|
||||
"""
|
||||
"""插件名称,使用 文件/文件夹 名称作为插件名"""
|
||||
module: ModuleType
|
||||
"""
|
||||
插件模块对象
|
||||
"""
|
||||
"""插件模块对象"""
|
||||
module_name: str
|
||||
"""
|
||||
点分割模块路径
|
||||
"""
|
||||
"""点分割模块路径"""
|
||||
manager: "PluginManager"
|
||||
"""
|
||||
导入该插件的插件管理器
|
||||
"""
|
||||
"""导入该插件的插件管理器"""
|
||||
export: Export = field(default_factory=Export)
|
||||
"""
|
||||
插件内定义的导出内容
|
||||
"""
|
||||
"""插件内定义的导出内容"""
|
||||
matcher: Set[Type[Matcher]] = field(default_factory=set)
|
||||
"""
|
||||
插件内定义的 `Matcher`
|
||||
"""
|
||||
"""插件内定义的 `Matcher`"""
|
||||
parent_plugin: Optional["Plugin"] = None
|
||||
"""
|
||||
父插件
|
||||
"""
|
||||
"""父插件"""
|
||||
sub_plugins: Set["Plugin"] = field(default_factory=set)
|
||||
"""
|
||||
子插件集合
|
||||
"""
|
||||
"""子插件集合"""
|
||||
|
||||
|
||||
def get_plugin(name: str) -> Optional[Plugin]:
|
||||
"""
|
||||
获取当前导入的某个插件。
|
||||
"""获取已经导入的某个插件。
|
||||
|
||||
如果为 `load_plugins` 文件夹导入的插件,则为文件(夹)名。
|
||||
|
||||
参数:
|
||||
name: 插件名,与 `load_plugin` 参数一致。如果为 `load_plugins` 导入的插件,则为文件(夹)名。
|
||||
name: 插件名,即 {ref}`nonebot.plugin.plugin.Plugin.name`。
|
||||
"""
|
||||
return plugins.get(name)
|
||||
|
||||
|
||||
def get_loaded_plugins() -> Set[Plugin]:
|
||||
"""
|
||||
获取当前已导入的所有插件。
|
||||
"""
|
||||
"""获取当前已导入的所有插件。"""
|
||||
return set(plugins.values())
|
||||
|
||||
|
||||
|
195
nonebot/rule.py
195
nonebot/rule.py
@ -1,11 +1,11 @@
|
||||
"""
|
||||
## 规则
|
||||
"""本模块是 {ref}`nonebot.matcher.Matcher.rule` 的类型定义。
|
||||
|
||||
每个事件响应器 `Matcher` 拥有一个匹配规则 `Rule` ,其中是 `RuleChecker` 的集合,只有当所有 `RuleChecker` 检查结果为 `True` 时继续运行。
|
||||
每个事件响应器 {ref}`nonebot.matcher.Matcher` 拥有一个匹配规则 {ref}`nonebot.rule.Rule`
|
||||
其中是 `RuleChecker` 的集合,只有当所有 `RuleChecker` 检查结果为 `True` 时继续运行。
|
||||
|
||||
::: tip 提示
|
||||
`RuleChecker` 既可以是 async function 也可以是 sync function
|
||||
:::
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.rule 模块
|
||||
"""
|
||||
|
||||
import re
|
||||
@ -42,6 +42,7 @@ from nonebot.params import (
|
||||
BotParam,
|
||||
EventToMe,
|
||||
EventType,
|
||||
CommandArg,
|
||||
EventParam,
|
||||
StateParam,
|
||||
DependParam,
|
||||
@ -61,15 +62,18 @@ CMD_RESULT = TypedDict(
|
||||
|
||||
|
||||
class Rule:
|
||||
"""
|
||||
`Matcher` 规则类,当事件传递时,在 `Matcher` 运行前进行检查。
|
||||
"""{ref}`nonebot.matcher.Matcher` 规则类。
|
||||
|
||||
当事件传递时,在 {ref}`nonebot.matcher.Matcher` 运行前进行检查。
|
||||
|
||||
参数:
|
||||
*checkers: RuleChecker
|
||||
|
||||
用法:
|
||||
```python
|
||||
Rule(async_function) & sync_function
|
||||
# 等价于
|
||||
from nonebot.utils import run_sync
|
||||
Rule(async_function, run_sync(sync_function))
|
||||
Rule(async_function, sync_function)
|
||||
```
|
||||
"""
|
||||
|
||||
@ -84,11 +88,6 @@ class Rule:
|
||||
]
|
||||
|
||||
def __init__(self, *checkers: Union[T_RuleChecker, Dependent[bool]]) -> None:
|
||||
"""
|
||||
参数:
|
||||
*checkers: RuleChecker
|
||||
|
||||
"""
|
||||
self.checkers: Set[Dependent[bool]] = set(
|
||||
checker
|
||||
if isinstance(checker, Dependent)
|
||||
@ -97,9 +96,7 @@ class Rule:
|
||||
)
|
||||
for checker in checkers
|
||||
)
|
||||
"""
|
||||
存储 `RuleChecker`
|
||||
"""
|
||||
"""存储 `RuleChecker`"""
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
@ -109,8 +106,7 @@ class Rule:
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否符合所有规则
|
||||
"""检查是否符合所有规则
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
@ -186,6 +182,15 @@ class TrieRule:
|
||||
|
||||
|
||||
class StartswithRule:
|
||||
"""检查消息纯文本是否以指定字符串开头。
|
||||
|
||||
参数:
|
||||
msg: 指定消息开头字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
|
||||
__slots__ = ("msg", "ignorecase")
|
||||
|
||||
def __init__(self, msg: Tuple[str, ...], ignorecase: bool = False):
|
||||
self.msg = msg
|
||||
self.ignorecase = ignorecase
|
||||
@ -205,11 +210,11 @@ class StartswithRule:
|
||||
|
||||
|
||||
def startswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Rule:
|
||||
"""
|
||||
匹配消息开头
|
||||
"""匹配消息纯文本开头。
|
||||
|
||||
参数:
|
||||
msg: 消息开头字符串
|
||||
msg: 指定消息开头字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
if isinstance(msg, str):
|
||||
msg = (msg,)
|
||||
@ -218,6 +223,15 @@ def startswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Ru
|
||||
|
||||
|
||||
class EndswithRule:
|
||||
"""检查消息纯文本是否以指定字符串结尾。
|
||||
|
||||
参数:
|
||||
msg: 指定消息结尾字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
|
||||
__slots__ = ("msg", "ignorecase")
|
||||
|
||||
def __init__(self, msg: Tuple[str, ...], ignorecase: bool = False):
|
||||
self.msg = msg
|
||||
self.ignorecase = ignorecase
|
||||
@ -237,11 +251,11 @@ class EndswithRule:
|
||||
|
||||
|
||||
def endswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Rule:
|
||||
"""
|
||||
匹配消息结尾
|
||||
"""匹配消息纯文本结尾。
|
||||
|
||||
参数:
|
||||
msg: 消息结尾字符串
|
||||
msg: 指定消息开头字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
if isinstance(msg, str):
|
||||
msg = (msg,)
|
||||
@ -250,6 +264,14 @@ def endswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Rule
|
||||
|
||||
|
||||
class KeywordsRule:
|
||||
"""检查消息纯文本是否包含指定关键字。
|
||||
|
||||
参数:
|
||||
keywords: 指定关键字元组
|
||||
"""
|
||||
|
||||
__slots__ = ("keywords",)
|
||||
|
||||
def __init__(self, *keywords: str):
|
||||
self.keywords = keywords
|
||||
|
||||
@ -262,17 +284,24 @@ class KeywordsRule:
|
||||
|
||||
|
||||
def keyword(*keywords: str) -> Rule:
|
||||
"""
|
||||
匹配消息关键词
|
||||
"""匹配消息纯文本关键词。
|
||||
|
||||
参数:
|
||||
*keywords: 关键词
|
||||
keywords: 指定关键字元组
|
||||
"""
|
||||
|
||||
return Rule(KeywordsRule(*keywords))
|
||||
|
||||
|
||||
class CommandRule:
|
||||
"""检查消息是否为指定命令。
|
||||
|
||||
参数:
|
||||
cmds: 指定命令元组列表
|
||||
"""
|
||||
|
||||
__slots__ = ("cmds",)
|
||||
|
||||
def __init__(self, cmds: List[Tuple[str, ...]]):
|
||||
self.cmds = cmds
|
||||
|
||||
@ -284,22 +313,26 @@ class CommandRule:
|
||||
|
||||
|
||||
def command(*cmds: Union[str, Tuple[str, ...]]) -> Rule:
|
||||
"""
|
||||
命令形式匹配,根据配置里提供的 `command_start`, `command_sep` 判断消息是否为命令。
|
||||
"""匹配消息命令。
|
||||
|
||||
可以通过 `state["_prefix"]["command"]` 获取匹配成功的命令(例:`("test",)`),通过 `state["_prefix"]["raw_command"]` 获取匹配成功的原始命令文本(例:`"/test"`)。
|
||||
根据配置里提供的 {ref}``command_start` <nonebot.config.Config.command_start>`,
|
||||
{ref}``command_sep` <nonebot.config.Config.command_sep>` 判断消息是否为命令。
|
||||
|
||||
可以通过 {ref}`nonebot.params.Command` 获取匹配成功的命令(例: `("test",)`),
|
||||
通过 {ref}`nonebot.params.RawCommand` 获取匹配成功的原始命令文本(例: `"/test"`),
|
||||
通过 {ref}`nonebot.params.CommandArg` 获取匹配成功的命令参数。
|
||||
|
||||
参数:
|
||||
*cmds: 命令内容
|
||||
cmds: 命令文本或命令元组
|
||||
|
||||
用法:
|
||||
使用默认 `command_start`, `command_sep` 配置
|
||||
|
||||
命令 `("test",)` 可以匹配:`/test` 开头的消息
|
||||
命令 `("test", "sub")` 可以匹配”`/test.sub` 开头的消息
|
||||
命令 `("test",)` 可以匹配: `/test` 开头的消息
|
||||
命令 `("test", "sub")` 可以匹配: `/test.sub` 开头的消息
|
||||
|
||||
::: tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::
|
||||
"""
|
||||
|
||||
@ -324,8 +357,11 @@ def command(*cmds: Union[str, Tuple[str, ...]]) -> Rule:
|
||||
|
||||
|
||||
class ArgumentParser(ArgParser):
|
||||
"""
|
||||
`shell_like` 命令参数解析器,解析出错时不会退出程序。
|
||||
"""`shell_like` 命令参数解析器,解析出错时不会退出程序。
|
||||
|
||||
用法:
|
||||
用法与 `argparse.ArgumentParser` 相同,
|
||||
参考文档: [argparse](https://docs.python.org/3/library/argparse.html)
|
||||
"""
|
||||
|
||||
def _print_message(self, message, file=None):
|
||||
@ -350,6 +386,15 @@ class ArgumentParser(ArgParser):
|
||||
|
||||
|
||||
class ShellCommandRule:
|
||||
"""检查消息是否为指定 shell 命令。
|
||||
|
||||
参数:
|
||||
cmds: 指定命令元组列表
|
||||
parser: 可选参数解析器
|
||||
"""
|
||||
|
||||
__slots__ = ("cmds", "parser")
|
||||
|
||||
def __init__(self, cmds: List[Tuple[str, ...]], parser: Optional[ArgumentParser]):
|
||||
self.cmds = cmds
|
||||
self.parser = parser
|
||||
@ -358,12 +403,11 @@ class ShellCommandRule:
|
||||
self,
|
||||
state: T_State,
|
||||
cmd: Optional[Tuple[str, ...]] = Command(),
|
||||
msg: Message = EventMessage(),
|
||||
msg: Optional[Message] = CommandArg(),
|
||||
) -> bool:
|
||||
if cmd in self.cmds:
|
||||
if cmd in self.cmds and msg is not None:
|
||||
message = str(msg)
|
||||
strip_message = message[len(state[PREFIX_KEY][RAW_CMD_KEY]) :].lstrip()
|
||||
state[SHELL_ARGV] = shlex.split(strip_message)
|
||||
state[SHELL_ARGV] = shlex.split(message)
|
||||
if self.parser:
|
||||
try:
|
||||
args = self.parser.parse_args(state[SHELL_ARGV])
|
||||
@ -378,18 +422,24 @@ class ShellCommandRule:
|
||||
def shell_command(
|
||||
*cmds: Union[str, Tuple[str, ...]], parser: Optional[ArgumentParser] = None
|
||||
) -> Rule:
|
||||
"""
|
||||
支持 `shell_like` 解析参数的命令形式匹配,根据配置里提供的 `command_start`, `command_sep` 判断消息是否为命令。
|
||||
"""匹配 `shell_like` 形式的消息命令。
|
||||
|
||||
可以通过 `state["_prefix"]["command"]` 获取匹配成功的命令(例:`("test",)`),通过 `state["_prefix"]["raw_command"]` 获取匹配成功的原始命令文本(例:`"/test"`)。
|
||||
根据配置里提供的 {ref}``command_start` <nonebot.config.Config.command_start>`,
|
||||
{ref}``command_sep` <nonebot.config.Config.command_sep>` 判断消息是否为命令。
|
||||
|
||||
可以通过 `state["argv"]` 获取用户输入的原始参数列表
|
||||
可以通过 {ref}`nonebot.params.Command` 获取匹配成功的命令(例: `("test",)`),
|
||||
通过 {ref}`nonebot.params.RawCommand` 获取匹配成功的原始命令文本(例: `"/test"`),
|
||||
通过 {ref}`nonebot.params.ShellCommandArgv` 获取解析前的参数列表(例: `["arg", "-h"]`),
|
||||
通过 {ref}`nonebot.params.ShellCommandArgs` 获取解析后的参数字典(例: `{"arg": "arg", "h": True}`)。
|
||||
|
||||
添加 `parser` 参数后, 可以自动处理消息并将结果保存在 `state["args"]` 中。
|
||||
:::warning 警告
|
||||
如果参数解析失败,则通过 {ref}`nonebot.params.ShellCommandArgs`
|
||||
获取的将是 {ref}`nonebot.exception.ParserExit` 异常。
|
||||
:::
|
||||
|
||||
参数:
|
||||
*cmds: 命令内容
|
||||
parser: `nonebot.rule.ArgumentParser` 对象
|
||||
cmds: 命令文本或命令元组
|
||||
parser: {ref}`nonebot.rule.ArgumentParser` 对象
|
||||
|
||||
用法:
|
||||
使用默认 `command_start`, `command_sep` 配置,更多示例参考 `argparse` 标准库文档。
|
||||
@ -403,8 +453,8 @@ def shell_command(
|
||||
rule = shell_command("ls", parser=parser)
|
||||
```
|
||||
|
||||
::: tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::
|
||||
"""
|
||||
if parser is not None and not isinstance(parser, ArgumentParser):
|
||||
@ -431,6 +481,15 @@ def shell_command(
|
||||
|
||||
|
||||
class RegexRule:
|
||||
"""检查消息字符串是否符合指定正则表达式。
|
||||
|
||||
参数:
|
||||
regex: 正则表达式
|
||||
flags: 正则表达式标记
|
||||
"""
|
||||
|
||||
__slots__ = ("regex", "flags")
|
||||
|
||||
def __init__(self, regex: str, flags: int = 0):
|
||||
self.regex = regex
|
||||
self.flags = flags
|
||||
@ -454,32 +513,46 @@ class RegexRule:
|
||||
|
||||
|
||||
def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule:
|
||||
"""
|
||||
根据正则表达式进行匹配。
|
||||
"""匹配符合正则表达式的消息字符串。
|
||||
|
||||
可以通过 `state["_matched"]` `state["_matched_groups"]` `state["_matched_dict"]`
|
||||
获取正则表达式匹配成功的文本。
|
||||
可以通过 {ref}`nonebot.params.RegexMatched` 获取匹配成功的字符串,
|
||||
通过 {ref}`nonebot.params.RegexGroup` 获取匹配成功的 group 元组,
|
||||
通过 {ref}`nonebot.params.RegexDict` 获取匹配成功的 group 字典。
|
||||
|
||||
参数:
|
||||
regex: 正则表达式
|
||||
flags: 正则标志
|
||||
flags: 正则表达式标记
|
||||
|
||||
::: tip 提示
|
||||
:::tip 提示
|
||||
正则表达式匹配使用 search 而非 match,如需从头匹配请使用 `r"^xxx"` 来确保匹配开头
|
||||
:::
|
||||
|
||||
:::tip 提示
|
||||
正则表达式匹配使用 `EventMessage` 的 `str` 字符串,而非 `EventMessage` 的 `PlainText` 纯文本字符串
|
||||
:::
|
||||
"""
|
||||
|
||||
return Rule(RegexRule(regex, flags))
|
||||
|
||||
|
||||
class ToMeRule:
|
||||
"""检查事件是否与机器人有关。"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, to_me: bool = EventToMe()) -> bool:
|
||||
return to_me
|
||||
|
||||
|
||||
def to_me() -> Rule:
|
||||
"""
|
||||
通过 `event.is_tome()` 判断事件是否与机器人有关
|
||||
"""
|
||||
"""匹配与机器人有关的事件。"""
|
||||
|
||||
return Rule(ToMeRule())
|
||||
|
||||
|
||||
__autodoc__ = {
|
||||
"Rule.__call__": True,
|
||||
"TrieRule": False,
|
||||
"ArgumentParser.exit": False,
|
||||
"ArgumentParser.parse_args": False,
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
"""
|
||||
## 类型
|
||||
"""本模块定义了 NoneBot 模块中共享的一些类型。
|
||||
|
||||
下面的文档中,「类型」部分使用 Python 的 Type Hint 语法,见 [`PEP 484`](https://www.python.org/dev/peps/pep-0484/)、[`PEP 526`](https://www.python.org/dev/peps/pep-0526/) 和 [`typing`](https://docs.python.org/3/library/typing.html)。
|
||||
下面的文档中,「类型」部分使用 Python 的 Type Hint 语法,
|
||||
参考 [`PEP 484`](https://www.python.org/dev/peps/pep-0484/),
|
||||
[`PEP 526`](https://www.python.org/dev/peps/pep-0526/) 和
|
||||
[`typing`](https://docs.python.org/3/library/typing.html)。
|
||||
|
||||
除了 Python 内置的类型,下面还出现了如下 NoneBot 自定类型,实际上它们是 Python 内置类型的别名。
|
||||
|
||||
以下类型均可从 nonebot.typing 模块导入。
|
||||
FrontMatter:
|
||||
sidebar_position: 11
|
||||
description: nonebot.typing 模块
|
||||
"""
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
@ -21,13 +25,15 @@ from typing import (
|
||||
if TYPE_CHECKING:
|
||||
from asyncio import Task
|
||||
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.permission import Permission
|
||||
|
||||
T_Wrapped = TypeVar("T_Wrapped", bound=Callable)
|
||||
|
||||
|
||||
def overrides(InterfaceClass: object):
|
||||
def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]:
|
||||
"""标记一个方法为父类 interface 的 implement"""
|
||||
|
||||
def overrider(func: T_Wrapped) -> T_Wrapped:
|
||||
assert func.__name__ in dir(InterfaceClass), f"Error method: {func.__name__}"
|
||||
return func
|
||||
@ -36,136 +42,114 @@ def overrides(InterfaceClass: object):
|
||||
|
||||
|
||||
T_State = Dict[Any, Any]
|
||||
"""
|
||||
事件处理状态 State 类型
|
||||
"""
|
||||
"""事件处理状态 State 类型"""
|
||||
|
||||
T_BotConnectionHook = Callable[["Bot"], Awaitable[None]]
|
||||
"""
|
||||
Bot 连接建立时执行的函数
|
||||
"""
|
||||
"""Bot 连接建立时钩子函数"""
|
||||
T_BotDisconnectionHook = Callable[["Bot"], Awaitable[None]]
|
||||
"""
|
||||
Bot 连接断开时执行的函数
|
||||
"""
|
||||
"""Bot 连接断开时钩子函数"""
|
||||
T_CallingAPIHook = Callable[["Bot", str, Dict[str, Any]], Awaitable[None]]
|
||||
"""
|
||||
`bot.call_api` 时执行的函数
|
||||
"""
|
||||
"""`bot.call_api` 钩子函数"""
|
||||
T_CalledAPIHook = Callable[
|
||||
["Bot", Optional[Exception], str, Dict[str, Any], Any], Awaitable[None]
|
||||
]
|
||||
"""
|
||||
`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result
|
||||
"""
|
||||
"""`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result"""
|
||||
|
||||
T_EventPreProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件预处理函数 EventPreProcessor 类型
|
||||
"""事件预处理函数 EventPreProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_EventPostProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件预处理函数 EventPostProcessor 类型
|
||||
"""事件预处理函数 EventPostProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_RunPreProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件响应器运行前预处理函数 RunPreProcessor 类型
|
||||
"""事件响应器运行前预处理函数 RunPreProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_RunPostProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件响应器运行前预处理函数 RunPostProcessor 类型,第二个参数为运行时产生的错误(如果存在)
|
||||
"""事件响应器运行前预处理函数 RunPostProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- ExceptionParam: 异常对象(可能为 None)
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- ExceptionParam: 异常对象(可能为 None)
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
|
||||
T_RuleChecker = Callable[..., Union[bool, Awaitable[bool]]]
|
||||
"""
|
||||
RuleChecker 即判断是否响应事件的处理函数。
|
||||
"""RuleChecker 即判断是否响应事件的处理函数。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_PermissionChecker = Callable[..., Union[bool, Awaitable[bool]]]
|
||||
"""
|
||||
RuleChecker 即判断是否响应消息的处理函数。
|
||||
"""PermissionChecker 即判断事件是否满足权限的处理函数。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
|
||||
T_Handler = Callable[..., Any]
|
||||
"""
|
||||
Handler 处理函数。
|
||||
"""
|
||||
"""Handler 处理函数。"""
|
||||
T_TypeUpdater = Callable[..., Union[str, Awaitable[str]]]
|
||||
"""
|
||||
TypeUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新响应的事件类型。默认会更新为 `message`。
|
||||
"""TypeUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新响应的事件类型。默认会更新为 `message`。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_PermissionUpdater = Callable[..., Union["Permission", Awaitable["Permission"]]]
|
||||
"""
|
||||
PermissionUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新会话对象权限。默认会更新为当前事件的触发对象。
|
||||
"""PermissionUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新会话对象权限。默认会更新为当前事件的触发对象。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_DependencyCache = Dict[Callable[..., Any], "Task[Any]"]
|
||||
"""
|
||||
依赖缓存, 用于存储依赖函数的返回值
|
||||
"""
|
||||
"""依赖缓存, 用于存储依赖函数的返回值"""
|
||||
|
@ -1,3 +1,10 @@
|
||||
"""本模块包含了 NoneBot 的一些工具函数
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 8
|
||||
description: nonebot.utils 模块
|
||||
"""
|
||||
|
||||
import re
|
||||
import json
|
||||
import asyncio
|
||||
@ -30,8 +37,9 @@ V = TypeVar("V")
|
||||
|
||||
|
||||
def escape_tag(s: str) -> str:
|
||||
"""
|
||||
用于记录带颜色日志时转义 `<tag>` 类型特殊标签
|
||||
"""用于记录带颜色日志时转义 `<tag>` 类型特殊标签
|
||||
|
||||
参考: [loguru color 标签](https://loguru.readthedocs.io/en/stable/api/logger.html#color)
|
||||
|
||||
参数:
|
||||
s: 需要转义的字符串
|
||||
@ -42,6 +50,7 @@ def escape_tag(s: str) -> str:
|
||||
def generic_check_issubclass(
|
||||
cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...]]
|
||||
) -> bool:
|
||||
"""检查 cls 是否是 class_or_tuple 中的一个类型子类或"""
|
||||
try:
|
||||
return issubclass(cls, class_or_tuple)
|
||||
except TypeError:
|
||||
@ -59,6 +68,7 @@ def generic_check_issubclass(
|
||||
|
||||
|
||||
def is_coroutine_callable(call: Callable[..., Any]) -> bool:
|
||||
"""检查 call 是否是一个 callable 协程函数"""
|
||||
if inspect.isroutine(call):
|
||||
return inspect.iscoroutinefunction(call)
|
||||
if inspect.isclass(call):
|
||||
@ -68,6 +78,7 @@ def is_coroutine_callable(call: Callable[..., Any]) -> bool:
|
||||
|
||||
|
||||
def is_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
"""检查 call 是否是一个生成器函数"""
|
||||
if inspect.isgeneratorfunction(call):
|
||||
return True
|
||||
func_ = getattr(call, "__call__", None)
|
||||
@ -75,6 +86,7 @@ def is_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
|
||||
|
||||
def is_async_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
"""检查 call 是否是一个异步生成器函数"""
|
||||
if inspect.isasyncgenfunction(call):
|
||||
return True
|
||||
func_ = getattr(call, "__call__", None)
|
||||
@ -82,8 +94,7 @@ def is_async_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
|
||||
|
||||
def run_sync(call: Callable[P, R]) -> Callable[P, Awaitable[R]]:
|
||||
"""
|
||||
一个用于包装 sync function 为 async function 的装饰器
|
||||
"""一个用于包装 sync function 为 async function 的装饰器
|
||||
|
||||
参数:
|
||||
call: 被装饰的同步函数
|
||||
@ -103,6 +114,7 @@ def run_sync(call: Callable[P, R]) -> Callable[P, Awaitable[R]]:
|
||||
async def run_sync_ctx_manager(
|
||||
cm: ContextManager[T],
|
||||
) -> AsyncGenerator[T, None]:
|
||||
"""一个用于包装 sync context manager 为 async context manager 的执行函数"""
|
||||
try:
|
||||
yield await run_sync(cm.__enter__)()
|
||||
except Exception as e:
|
||||
@ -114,15 +126,14 @@ async def run_sync_ctx_manager(
|
||||
|
||||
|
||||
def get_name(obj: Any) -> str:
|
||||
"""获取对象的名称"""
|
||||
if inspect.isfunction(obj) or inspect.isclass(obj):
|
||||
return obj.__name__
|
||||
return obj.__class__.__name__
|
||||
|
||||
|
||||
class DataclassEncoder(json.JSONEncoder):
|
||||
"""
|
||||
在JSON序列化 `Message` (List[Dataclass]) 时使用的 `JSONEncoder`
|
||||
"""
|
||||
"""在JSON序列化 {re}`nonebot.adapters._message.Message` (List[Dataclass]) 时使用的 `JSONEncoder`"""
|
||||
|
||||
@overrides(json.JSONEncoder)
|
||||
def default(self, o):
|
||||
@ -131,14 +142,18 @@ class DataclassEncoder(json.JSONEncoder):
|
||||
return super().default(o)
|
||||
|
||||
|
||||
def logger_wrapper(logger_name: str):
|
||||
"""
|
||||
用于打印 adapter 的日志。
|
||||
def logger_wrapper(logger_name: str) -> Callable[[str, str, Optional[Exception]], None]:
|
||||
"""用于打印 adapter 的日志。
|
||||
|
||||
参数:
|
||||
level: 日志等级
|
||||
message: 日志信息
|
||||
exception: 异常信息
|
||||
logger_name: adapter 的名称
|
||||
|
||||
返回:
|
||||
日志记录函数
|
||||
|
||||
- level: 日志等级
|
||||
- message: 日志信息
|
||||
- exception: 异常信息
|
||||
"""
|
||||
|
||||
def log(level: str, message: str, exception: Optional[Exception] = None):
|
||||
|
505
poetry.lock
generated
505
poetry.lock
generated
@ -53,14 +53,6 @@ python-versions = ">=3.6"
|
||||
[package.dependencies]
|
||||
frozenlist = ">=1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "alabaster"
|
||||
version = "0.7.12"
|
||||
description = "A configurable sidebar-enabled Sphinx theme"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "3.5.0"
|
||||
@ -81,11 +73,11 @@ trio = ["trio (>=0.16)"]
|
||||
|
||||
[[package]]
|
||||
name = "asgiref"
|
||||
version = "3.4.1"
|
||||
version = "3.5.0"
|
||||
description = "ASGI specs, helper code, and adapters"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
|
||||
@ -146,17 +138,6 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
|
||||
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
|
||||
|
||||
[[package]]
|
||||
name = "babel"
|
||||
version = "2.9.1"
|
||||
description = "Internationalization utilities"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[package.dependencies]
|
||||
pytz = ">=2015.7"
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "21.12b0"
|
||||
@ -288,14 +269,6 @@ category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "docutils"
|
||||
version = "0.17.1"
|
||||
description = "Docutils -- Python Documentation Utilities"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "execnet"
|
||||
version = "1.9.0"
|
||||
@ -339,11 +312,11 @@ testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-co
|
||||
|
||||
[[package]]
|
||||
name = "frozenlist"
|
||||
version = "1.2.0"
|
||||
version = "1.3.0"
|
||||
description = "A list-like structure which implements collections.abc.MutableSequence"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
@ -373,17 +346,9 @@ category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.6.1"
|
||||
|
||||
[[package]]
|
||||
name = "html2text"
|
||||
version = "2020.1.16"
|
||||
description = "Turn HTML into equivalent Markdown-structured text."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "0.14.4"
|
||||
version = "0.14.5"
|
||||
description = "A minimal low-level HTTP client."
|
||||
category = "main"
|
||||
optional = true
|
||||
@ -397,6 +362,7 @@ sniffio = ">=1.0.0,<2.0.0"
|
||||
|
||||
[package.extras]
|
||||
http2 = ["h2 (>=3,<5)"]
|
||||
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "httptools"
|
||||
@ -478,17 +444,9 @@ category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "imagesize"
|
||||
version = "1.3.0"
|
||||
description = "Getting image size from png/jpeg/jpeg2000/gif file"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "4.10.0"
|
||||
version = "4.10.1"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -538,7 +496,7 @@ name = "jinja2"
|
||||
version = "3.0.3"
|
||||
description = "A very fast and expressive template engine."
|
||||
category = "main"
|
||||
optional = false
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
@ -567,7 +525,7 @@ name = "markupsafe"
|
||||
version = "2.0.1"
|
||||
description = "Safely add untrusted strings to HTML/XML markup."
|
||||
category = "main"
|
||||
optional = false
|
||||
optional = true
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
@ -586,6 +544,26 @@ category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "nb-autodoc"
|
||||
version = "0.1.0"
|
||||
description = "API doc generator for NoneBot."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=21.4,<22.0"
|
||||
click = ">=8.0.3"
|
||||
six = ">=1.6.1"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/nonebot/nb-autodoc.git"
|
||||
reference = "master"
|
||||
resolved_reference = "4d10247b74d3559f3cc05367e135c49097933028"
|
||||
|
||||
[[package]]
|
||||
name = "nodeenv"
|
||||
version = "1.6.0"
|
||||
@ -664,7 +642,7 @@ testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "pre-commit"
|
||||
version = "2.16.0"
|
||||
version = "2.17.0"
|
||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -733,25 +711,6 @@ typing-extensions = ">=3.7.4.3"
|
||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||
email = ["email-validator (>=1.0.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydash"
|
||||
version = "5.1.0"
|
||||
description = "The kitchen sink of Python utility libraries for doing \"stuff\" in a functional way. Based on the Lo-Dash Javascript library."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
dev = ["black", "coverage", "docformatter", "flake8", "flake8-black", "flake8-bugbear", "flake8-isort", "invoke", "isort", "pylint", "pytest", "pytest-cov", "pytest-flake8", "pytest-pylint", "sphinx", "sphinx-rtd-theme", "tox", "twine", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.11.2"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "pygtrie"
|
||||
version = "2.4.2"
|
||||
@ -762,7 +721,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.6"
|
||||
version = "3.0.7"
|
||||
description = "Python parsing module"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -863,14 +822,6 @@ python-versions = ">=3.5"
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2021.3"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0"
|
||||
@ -950,138 +901,6 @@ category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "snowballstemmer"
|
||||
version = "2.2.0"
|
||||
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "sphinx"
|
||||
version = "4.3.2"
|
||||
description = "Python documentation generator"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
alabaster = ">=0.7,<0.8"
|
||||
babel = ">=1.3"
|
||||
colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""}
|
||||
docutils = ">=0.14,<0.18"
|
||||
imagesize = "*"
|
||||
Jinja2 = ">=2.3"
|
||||
packaging = "*"
|
||||
Pygments = ">=2.0"
|
||||
requests = ">=2.5.0"
|
||||
snowballstemmer = ">=1.1"
|
||||
sphinxcontrib-applehelp = "*"
|
||||
sphinxcontrib-devhelp = "*"
|
||||
sphinxcontrib-htmlhelp = ">=2.0.0"
|
||||
sphinxcontrib-jsmath = "*"
|
||||
sphinxcontrib-qthelp = "*"
|
||||
sphinxcontrib-serializinghtml = ">=1.1.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinxcontrib-websupport"]
|
||||
lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.920)", "docutils-stubs", "types-typed-ast", "types-pkg-resources", "types-requests"]
|
||||
test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"]
|
||||
|
||||
[[package]]
|
||||
name = "sphinx-markdown-builder"
|
||||
version = "0.5.4"
|
||||
description = "sphinx builder that outputs markdown files"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
html2text = "*"
|
||||
pydash = "*"
|
||||
sphinx = "*"
|
||||
unify = "*"
|
||||
yapf = "*"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/nonebot/sphinx-markdown-builder.git"
|
||||
reference = "master"
|
||||
resolved_reference = "2204923f5938a8f7354c6a69ed58079edd180a43"
|
||||
|
||||
[[package]]
|
||||
name = "sphinxcontrib-applehelp"
|
||||
version = "1.0.2"
|
||||
description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.extras]
|
||||
lint = ["flake8", "mypy", "docutils-stubs"]
|
||||
test = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "sphinxcontrib-devhelp"
|
||||
version = "1.0.2"
|
||||
description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.extras]
|
||||
lint = ["flake8", "mypy", "docutils-stubs"]
|
||||
test = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "sphinxcontrib-htmlhelp"
|
||||
version = "2.0.0"
|
||||
description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
lint = ["flake8", "mypy", "docutils-stubs"]
|
||||
test = ["pytest", "html5lib"]
|
||||
|
||||
[[package]]
|
||||
name = "sphinxcontrib-jsmath"
|
||||
version = "1.0.1"
|
||||
description = "A sphinx extension which renders display math in HTML via JavaScript"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest", "flake8", "mypy"]
|
||||
|
||||
[[package]]
|
||||
name = "sphinxcontrib-qthelp"
|
||||
version = "1.0.3"
|
||||
description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.extras]
|
||||
lint = ["flake8", "mypy", "docutils-stubs"]
|
||||
test = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "sphinxcontrib-serializinghtml"
|
||||
version = "1.1.5"
|
||||
description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.extras]
|
||||
lint = ["flake8", "mypy", "docutils-stubs"]
|
||||
test = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.16.0"
|
||||
@ -1137,25 +956,6 @@ category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "unify"
|
||||
version = "0.5"
|
||||
description = "Modifies strings to all use the same (single/double) quote where possible."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
untokenize = "*"
|
||||
|
||||
[[package]]
|
||||
name = "untokenize"
|
||||
version = "0.1.1"
|
||||
description = "Transforms tokens into original source code (while preserving whitespace)."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.8"
|
||||
@ -1254,7 +1054,7 @@ watchdog = ["watchdog"]
|
||||
|
||||
[[package]]
|
||||
name = "win32-setctime"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0"
|
||||
description = "A small Python utility to set file creation time on Windows"
|
||||
category = "main"
|
||||
optional = false
|
||||
@ -1274,14 +1074,6 @@ python-versions = ">=3.6.1"
|
||||
[package.dependencies]
|
||||
h11 = ">=0.9.0,<1"
|
||||
|
||||
[[package]]
|
||||
name = "yapf"
|
||||
version = "0.32.0"
|
||||
description = "A formatter for Python code."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "yarl"
|
||||
version = "1.7.2"
|
||||
@ -1317,7 +1109,7 @@ websockets = ["websockets"]
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.7.3"
|
||||
content-hash = "a7b56ed800a11b847b85c23f507d2bdb6fda127d32b5468d0cc43d2ac79ea659"
|
||||
content-hash = "b18b98c20de891dfd80f15ac896f13ed529264dd4913ed1ca9cccff3fee379ba"
|
||||
|
||||
[metadata.files]
|
||||
aiodns = [
|
||||
@ -1406,17 +1198,13 @@ aiosignal = [
|
||||
{file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"},
|
||||
{file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"},
|
||||
]
|
||||
alabaster = [
|
||||
{file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
|
||||
{file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
|
||||
]
|
||||
anyio = [
|
||||
{file = "anyio-3.5.0-py3-none-any.whl", hash = "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e"},
|
||||
{file = "anyio-3.5.0.tar.gz", hash = "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6"},
|
||||
]
|
||||
asgiref = [
|
||||
{file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"},
|
||||
{file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"},
|
||||
{file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"},
|
||||
{file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"},
|
||||
]
|
||||
async-asgi-testclient = [
|
||||
{file = "async-asgi-testclient-1.4.9.tar.gz", hash = "sha256:ae507f44a53699611cff81ad548090dad24055fba02cce398e1ca9b84d1e1288"},
|
||||
@ -1437,10 +1225,6 @@ attrs = [
|
||||
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
|
||||
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
|
||||
]
|
||||
babel = [
|
||||
{file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"},
|
||||
{file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
|
||||
]
|
||||
black = [
|
||||
{file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
|
||||
{file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
|
||||
@ -1653,10 +1437,6 @@ distlib = [
|
||||
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
|
||||
{file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
|
||||
]
|
||||
docutils = [
|
||||
{file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"},
|
||||
{file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
|
||||
]
|
||||
execnet = [
|
||||
{file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"},
|
||||
{file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"},
|
||||
@ -1670,78 +1450,65 @@ filelock = [
|
||||
{file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"},
|
||||
]
|
||||
frozenlist = [
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:977a1438d0e0d96573fd679d291a1542097ea9f4918a8b6494b06610dfeefbf9"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8d86547a5e98d9edd47c432f7a14b0c5592624b496ae9880fb6332f34af1edc"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:181754275d5d32487431a0a29add4f897968b7157204bc1eaaf0a0ce80c5ba7d"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5df31bb2b974f379d230a25943d9bf0d3bc666b4b0807394b131a28fca2b0e5f"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4766632cd8a68e4f10f156a12c9acd7b1609941525569dd3636d859d79279ed3"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16eef427c51cb1203a7c0ab59d1b8abccaba9a4f58c4bfca6ed278fc896dc193"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:01d79515ed5aa3d699b05f6bdcf1fe9087d61d6b53882aa599a10853f0479c6c"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:28e164722ea0df0cf6d48c4d5bdf3d19e87aaa6dfb39b0ba91153f224b912020"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e63ad0beef6ece06475d29f47d1f2f29727805376e09850ebf64f90777962792"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41de4db9b9501679cf7cddc16d07ac0f10ef7eb58c525a1c8cbff43022bddca4"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c6a9d84ee6427b65a81fc24e6ef589cb794009f5ca4150151251c062773e7ed2"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:f5f3b2942c3b8b9bfe76b408bbaba3d3bb305ee3693e8b1d631fe0a0d4f93673"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c98d3c04701773ad60d9545cd96df94d955329efc7743fdb96422c4b669c633b"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-win32.whl", hash = "sha256:72cfbeab7a920ea9e74b19aa0afe3b4ad9c89471e3badc985d08756efa9b813b"},
|
||||
{file = "frozenlist-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:11ff401951b5ac8c0701a804f503d72c048173208490c54ebb8d7bb7c07a6d00"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b46f997d5ed6d222a863b02cdc9c299101ee27974d9bbb2fd1b3c8441311c408"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351686ca020d1bcd238596b1fa5c8efcbc21bffda9d0efe237aaa60348421e2a"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfbaa08cf1452acad9cb1c1d7b89394a41e712f88df522cea1a0f296b57782a0"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2ae2f5e9fa10805fb1c9adbfefaaecedd9e31849434be462c3960a0139ed729"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6790b8d96bbb74b7a6f4594b6f131bd23056c25f2aa5d816bd177d95245a30e3"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:41f62468af1bd4e4b42b5508a3fe8cc46a693f0cdd0ca2f443f51f207893d837"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:ec6cf345771cdb00791d271af9a0a6fbfc2b6dd44cb753f1eeaa256e21622adb"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:14a5cef795ae3e28fb504b73e797c1800e9249f950e1c964bb6bdc8d77871161"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8b54cdd2fda15467b9b0bfa78cee2ddf6dbb4585ef23a16e14926f4b076dfae4"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f025f1d6825725b09c0038775acab9ae94264453a696cc797ce20c0769a7b367"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:84e97f59211b5b9083a2e7a45abf91cfb441369e8bb6d1f5287382c1c526def3"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-win32.whl", hash = "sha256:c5328ed53fdb0a73c8a50105306a3bc013e5ca36cca714ec4f7bd31d38d8a97f"},
|
||||
{file = "frozenlist-1.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9ade70aea559ca98f4b1b1e5650c45678052e76a8ab2f76d90f2ac64180215a2"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0d3ffa8772464441b52489b985d46001e2853a3b082c655ec5fad9fb6a3d618"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3457f8cf86deb6ce1ba67e120f1b0128fcba1332a180722756597253c465fc1d"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a72eecf37eface331636951249d878750db84034927c997d47f7f78a573b72b"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:acc4614e8d1feb9f46dd829a8e771b8f5c4b1051365d02efb27a3229048ade8a"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:87521e32e18a2223311afc2492ef2d99946337da0779ddcda77b82ee7319df59"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b4c7665a17c3a5430edb663e4ad4e1ad457614d1b2f2b7f87052e2ef4fa45ca"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ed58803563a8c87cf4c0771366cf0ad1aa265b6b0ae54cbbb53013480c7ad74d"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa44c4740b4e23fcfa259e9dd52315d2b1770064cde9507457e4c4a65a04c397"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2de5b931701257d50771a032bba4e448ff958076380b049fd36ed8738fdb375b"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6e105013fa84623c057a4381dc8ea0361f4d682c11f3816cc80f49a1f3bc17c6"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:705c184b77565955a99dc360f359e8249580c6b7eaa4dc0227caa861ef46b27a"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:a37594ad6356e50073fe4f60aa4187b97d15329f2138124d252a5a19c8553ea4"},
|
||||
{file = "frozenlist-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:25b358aaa7dba5891b05968dd539f5856d69f522b6de0bf34e61f133e077c1a4"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af2a51c8a381d76eabb76f228f565ed4c3701441ecec101dd18be70ebd483cfd"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:82d22f6e6f2916e837c91c860140ef9947e31194c82aaeda843d6551cec92f19"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cfe6fef507f8bac40f009c85c7eddfed88c1c0d38c75e72fe10476cef94e10f"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f602e380a5132880fa245c92030abb0fc6ff34e0c5500600366cedc6adb06a"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ad065b2ebd09f32511ff2be35c5dfafee6192978b5a1e9d279a5c6e121e3b03"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bc93f5f62df3bdc1f677066327fc81f92b83644852a31c6aa9b32c2dde86ea7d"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:89fdfc84c6bf0bff2ff3170bb34ecba8a6911b260d318d377171429c4be18c73"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:47b2848e464883d0bbdcd9493c67443e5e695a84694efff0476f9059b4cb6257"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4f52d0732e56906f8ddea4bd856192984650282424049c956857fed43697ea43"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:16ef7dd5b7d17495404a2e7a49bac1bc13d6d20c16d11f4133c757dd94c4144c"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1cf63243bc5f5c19762943b0aa9e0d3fb3723d0c514d820a18a9b9a5ef864315"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:54a1e09ab7a69f843cd28fefd2bcaf23edb9e3a8d7680032c8968b8ac934587d"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:954b154a4533ef28bd3e83ffdf4eadf39deeda9e38fb8feaf066d6069885e034"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-win32.whl", hash = "sha256:cb3957c39668d10e2b486acc85f94153520a23263b6401e8f59422ef65b9520d"},
|
||||
{file = "frozenlist-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0a7c7cce70e41bc13d7d50f0e5dd175f14a4f1837a8549b0936ed0cbe6170bf9"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4c457220468d734e3077580a3642b7f682f5fd9507f17ddf1029452450912cdc"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e74f8b4d8677ebb4015ac01fcaf05f34e8a1f22775db1f304f497f2f88fdc697"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fbd4844ff111449f3bbe20ba24fbb906b5b1c2384d0f3287c9f7da2354ce6d23"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0081a623c886197ff8de9e635528fd7e6a387dccef432149e25c13946cb0cd0"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b6e21e5770df2dea06cb7b6323fbc008b13c4a4e3b52cb54685276479ee7676"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:406aeb340613b4b559db78d86864485f68919b7141dec82aba24d1477fd2976f"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:878ebe074839d649a1cdb03a61077d05760624f36d196884a5cafb12290e187b"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1fef737fd1388f9b93bba8808c5f63058113c10f4e3c0763ced68431773f72f9"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a495c3d513573b0b3f935bfa887a85d9ae09f0627cf47cad17d0cc9b9ba5c38"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e7d0dd3e727c70c2680f5f09a0775525229809f1a35d8552b92ff10b2b14f2c2"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:66a518731a21a55b7d3e087b430f1956a36793acc15912e2878431c7aec54210"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:94728f97ddf603d23c8c3dd5cae2644fa12d33116e69f49b1644a71bb77b89ae"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c1e8e9033d34c2c9e186e58279879d78c94dd365068a3607af33f2bc99357a53"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-win32.whl", hash = "sha256:83334e84a290a158c0c4cc4d22e8c7cfe0bba5b76d37f1c2509dabd22acafe15"},
|
||||
{file = "frozenlist-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:735f386ec522e384f511614c01d2ef9cf799f051353876b4c6fb93ef67a6d1ee"},
|
||||
{file = "frozenlist-1.2.0.tar.gz", hash = "sha256:68201be60ac56aff972dc18085800b6ee07973c49103a8aba669dee3d71079de"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2257aaba9660f78c7b1d8fea963b68f3feffb1a9d5d05a18401ca9eb3e8d0a3"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4a44ebbf601d7bac77976d429e9bdb5a4614f9f4027777f9e54fd765196e9d3b"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:45334234ec30fc4ea677f43171b18a27505bfb2dba9aca4398a62692c0ea8868"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47be22dc27ed933d55ee55845d34a3e4e9f6fee93039e7f8ebadb0c2f60d403f"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03a7dd1bfce30216a3f51a84e6dd0e4a573d23ca50f0346634916ff105ba6e6b"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:691ddf6dc50480ce49f68441f1d16a4c3325887453837036e0fb94736eae1e58"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bde99812f237f79eaf3f04ebffd74f6718bbd216101b35ac7955c2d47c17da02"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a202458d1298ced3768f5a7d44301e7c86defac162ace0ab7434c2e961166e8"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9e3e9e365991f8cc5f5edc1fd65b58b41d0514a6a7ad95ef5c7f34eb49b3d3e"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:04cb491c4b1c051734d41ea2552fde292f5f3a9c911363f74f39c23659c4af78"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:436496321dad302b8b27ca955364a439ed1f0999311c393dccb243e451ff66aa"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:754728d65f1acc61e0f4df784456106e35afb7bf39cfe37227ab00436fb38676"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6eb275c6385dd72594758cbe96c07cdb9bd6becf84235f4a594bdf21e3596c9d"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-win32.whl", hash = "sha256:e30b2f9683812eb30cf3f0a8e9f79f8d590a7999f731cf39f9105a7c4a39489d"},
|
||||
{file = "frozenlist-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f7353ba3367473d1d616ee727945f439e027f0bb16ac1a750219a8344d1d5d3c"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88aafd445a233dbbf8a65a62bc3249a0acd0d81ab18f6feb461cc5a938610d24"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4406cfabef8f07b3b3af0f50f70938ec06d9f0fc26cbdeaab431cbc3ca3caeaa"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf829bd2e2956066dd4de43fd8ec881d87842a06708c035b37ef632930505a2"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:603b9091bd70fae7be28bdb8aa5c9990f4241aa33abb673390a7f7329296695f"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25af28b560e0c76fa41f550eacb389905633e7ac02d6eb3c09017fa1c8cdfde1"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c7a8a9fc9383b52c410a2ec952521906d355d18fccc927fca52ab575ee8b93"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:65bc6e2fece04e2145ab6e3c47428d1bbc05aede61ae365b2c1bddd94906e478"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3f7c935c7b58b0d78c0beea0c7358e165f95f1fd8a7e98baa40d22a05b4a8141"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd89acd1b8bb4f31b47072615d72e7f53a948d302b7c1d1455e42622de180eae"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6983a31698490825171be44ffbafeaa930ddf590d3f051e397143a5045513b01"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:adac9700675cf99e3615eb6a0eb5e9f5a4143c7d42c05cea2e7f71c27a3d0846"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-win32.whl", hash = "sha256:0c36e78b9509e97042ef869c0e1e6ef6429e55817c12d78245eb915e1cca7468"},
|
||||
{file = "frozenlist-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:57f4d3f03a18facacb2a6bcd21bccd011e3b75d463dc49f838fd699d074fabd1"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8c905a5186d77111f02144fab5b849ab524f1e876a1e75205cd1386a9be4b00a"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5009062d78a8c6890d50b4e53b0ddda31841b3935c1937e2ed8c1bda1c7fb9d"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2fdc3cd845e5a1f71a0c3518528bfdbfe2efaf9886d6f49eacc5ee4fd9a10953"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e650bd09b5dda929523b9f8e7f99b24deac61240ecc1a32aeba487afcd970f"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40dff8962b8eba91fd3848d857203f0bd704b5f1fa2b3fc9af64901a190bba08"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:768efd082074bb203c934e83a61654ed4931ef02412c2fbdecea0cff7ecd0274"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:006d3595e7d4108a12025ddf415ae0f6c9e736e726a5db0183326fd191b14c5e"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:871d42623ae15eb0b0e9df65baeee6976b2e161d0ba93155411d58ff27483ad8"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aff388be97ef2677ae185e72dc500d19ecaf31b698986800d3fc4f399a5e30a5"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9f892d6a94ec5c7b785e548e42722e6f3a52f5f32a8461e82ac3e67a3bd073f1"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e982878792c971cbd60ee510c4ee5bf089a8246226dea1f2138aa0bb67aff148"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c6c321dd013e8fc20735b92cb4892c115f5cdb82c817b1e5b07f6b95d952b2f0"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:30530930410855c451bea83f7b272fb1c495ed9d5cc72895ac29e91279401db3"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-win32.whl", hash = "sha256:40ec383bc194accba825fbb7d0ef3dda5736ceab2375462f1d8672d9f6b68d07"},
|
||||
{file = "frozenlist-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:f20baa05eaa2bcd5404c445ec51aed1c268d62600362dc6cfe04fae34a424bd9"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0437fe763fb5d4adad1756050cbf855bbb2bf0d9385c7bb13d7a10b0dd550486"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b684c68077b84522b5c7eafc1dc735bfa5b341fb011d5552ebe0968e22ed641c"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93641a51f89473837333b2f8100f3f89795295b858cd4c7d4a1f18e299dc0a4f"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6d32ff213aef0fd0bcf803bffe15cfa2d4fde237d1d4838e62aec242a8362fa"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31977f84828b5bb856ca1eb07bf7e3a34f33a5cddce981d880240ba06639b94d"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c62964192a1c0c30b49f403495911298810bada64e4f03249ca35a33ca0417a"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4eda49bea3602812518765810af732229b4291d2695ed24a0a20e098c45a707b"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acb267b09a509c1df5a4ca04140da96016f40d2ed183cdc356d237286c971b51"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e1e26ac0a253a2907d654a37e390904426d5ae5483150ce3adedb35c8c06614a"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f96293d6f982c58ebebb428c50163d010c2f05de0cde99fd681bfdc18d4b2dc2"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e84cb61b0ac40a0c3e0e8b79c575161c5300d1d89e13c0e02f76193982f066ed"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:ff9310f05b9d9c5c4dd472983dc956901ee6cb2c3ec1ab116ecdde25f3ce4951"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d26b650b71fdc88065b7a21f8ace70175bcf3b5bdba5ea22df4bfd893e795a3b"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-win32.whl", hash = "sha256:01a73627448b1f2145bddb6e6c2259988bb8aee0fb361776ff8604b99616cd08"},
|
||||
{file = "frozenlist-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:772965f773757a6026dea111a15e6e2678fbd6216180f82a48a40b27de1ee2ab"},
|
||||
{file = "frozenlist-1.3.0.tar.gz", hash = "sha256:ce6f2ba0edb7b0c1d8976565298ad2deba6f8064d2bebb6ffce2ca896eb35b0b"},
|
||||
]
|
||||
h11 = [
|
||||
{file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
|
||||
@ -1755,13 +1522,9 @@ hpack = [
|
||||
{file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"},
|
||||
{file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"},
|
||||
]
|
||||
html2text = [
|
||||
{file = "html2text-2020.1.16-py3-none-any.whl", hash = "sha256:c7c629882da0cf377d66f073329ccf34a12ed2adf0169b9285ae4e63ef54c82b"},
|
||||
{file = "html2text-2020.1.16.tar.gz", hash = "sha256:e296318e16b059ddb97f7a8a1d6a5c1d7af4544049a01e261731d2d5cc277bbb"},
|
||||
]
|
||||
httpcore = [
|
||||
{file = "httpcore-0.14.4-py3-none-any.whl", hash = "sha256:9410fe352bea732311f2b2bee0555c8cc5e62b9a73b9d3272fe125a2aa6eb28e"},
|
||||
{file = "httpcore-0.14.4.tar.gz", hash = "sha256:d4305811f604d3c2e22869147392f134796976ff946c96a8cfba87f4e0171d83"},
|
||||
{file = "httpcore-0.14.5-py3-none-any.whl", hash = "sha256:2621ee769d0236574df51b305c5f4c69ca8f0c7b215221ad247b1ee42a9a9de1"},
|
||||
{file = "httpcore-0.14.5.tar.gz", hash = "sha256:435ab519628a6e2393f67812dea3ca5c6ad23b457412cd119295d9f906d96a2b"},
|
||||
]
|
||||
httptools = [
|
||||
{file = "httptools-0.2.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:79dbc21f3612a78b28384e989b21872e2e3cf3968532601544696e4ed0007ce5"},
|
||||
@ -1800,13 +1563,9 @@ idna = [
|
||||
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
|
||||
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||
]
|
||||
imagesize = [
|
||||
{file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"},
|
||||
{file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-4.10.0-py3-none-any.whl", hash = "sha256:b7cf7d3fef75f1e4c80a96ca660efbd51473d7e8f39b5ab9210febc7809012a4"},
|
||||
{file = "importlib_metadata-4.10.0.tar.gz", hash = "sha256:92a8b58ce734b2a4494878e0ecf7d79ccd7a128b5fc6014c401e0b61f006f0f6"},
|
||||
{file = "importlib_metadata-4.10.1-py3-none-any.whl", hash = "sha256:899e2a40a8c4a1aec681feef45733de8a6c58f3f6a0dbed2eb6574b4387a77b6"},
|
||||
{file = "importlib_metadata-4.10.1.tar.gz", hash = "sha256:951f0d8a5b7260e9db5e41d429285b5f451e928479f19d80818878527d36e95e"},
|
||||
]
|
||||
iniconfig = [
|
||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||
@ -1977,6 +1736,7 @@ mypy-extensions = [
|
||||
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
|
||||
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
||||
]
|
||||
nb-autodoc = []
|
||||
nodeenv = [
|
||||
{file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"},
|
||||
{file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
|
||||
@ -1999,8 +1759,8 @@ pluggy = [
|
||||
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||
]
|
||||
pre-commit = [
|
||||
{file = "pre_commit-2.16.0-py2.py3-none-any.whl", hash = "sha256:758d1dc9b62c2ed8881585c254976d66eae0889919ab9b859064fc2fe3c7743e"},
|
||||
{file = "pre_commit-2.16.0.tar.gz", hash = "sha256:fe9897cac830aa7164dbd02a4e7b90cae49630451ce88464bca73db486ba9f65"},
|
||||
{file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"},
|
||||
{file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"},
|
||||
]
|
||||
priority = [
|
||||
{file = "priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa"},
|
||||
@ -2084,20 +1844,12 @@ pydantic = [
|
||||
{file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"},
|
||||
{file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"},
|
||||
]
|
||||
pydash = [
|
||||
{file = "pydash-5.1.0-py3-none-any.whl", hash = "sha256:ced4fedb163eb07fbee376e474bca74029eb9fab215614449fe13164f71dd9e3"},
|
||||
{file = "pydash-5.1.0.tar.gz", hash = "sha256:1b2b050ac1bae049cd07f5920b14fabbe52638f485d9ada1eb115a9eebff6835"},
|
||||
]
|
||||
pygments = [
|
||||
{file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"},
|
||||
{file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
|
||||
]
|
||||
pygtrie = [
|
||||
{file = "pygtrie-2.4.2.tar.gz", hash = "sha256:43205559d28863358dbbf25045029f58e2ab357317a59b11f11ade278ac64692"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
|
||||
{file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
|
||||
{file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
|
||||
{file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
|
||||
]
|
||||
pytest = [
|
||||
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
|
||||
@ -2123,10 +1875,6 @@ python-dotenv = [
|
||||
{file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"},
|
||||
{file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"},
|
||||
]
|
||||
pytz = [
|
||||
{file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
|
||||
{file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
|
||||
]
|
||||
pyyaml = [
|
||||
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
|
||||
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
|
||||
@ -2182,39 +1930,6 @@ sniffio = [
|
||||
{file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"},
|
||||
{file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"},
|
||||
]
|
||||
snowballstemmer = [
|
||||
{file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
|
||||
{file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
|
||||
]
|
||||
sphinx = [
|
||||
{file = "Sphinx-4.3.2-py3-none-any.whl", hash = "sha256:6a11ea5dd0bdb197f9c2abc2e0ce73e01340464feaece525e64036546d24c851"},
|
||||
{file = "Sphinx-4.3.2.tar.gz", hash = "sha256:0a8836751a68306b3fe97ecbe44db786f8479c3bf4b80e3a7f5c838657b4698c"},
|
||||
]
|
||||
sphinx-markdown-builder = []
|
||||
sphinxcontrib-applehelp = [
|
||||
{file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
|
||||
{file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"},
|
||||
]
|
||||
sphinxcontrib-devhelp = [
|
||||
{file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"},
|
||||
{file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"},
|
||||
]
|
||||
sphinxcontrib-htmlhelp = [
|
||||
{file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"},
|
||||
{file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"},
|
||||
]
|
||||
sphinxcontrib-jsmath = [
|
||||
{file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
|
||||
{file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
|
||||
]
|
||||
sphinxcontrib-qthelp = [
|
||||
{file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"},
|
||||
{file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"},
|
||||
]
|
||||
sphinxcontrib-serializinghtml = [
|
||||
{file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"},
|
||||
{file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"},
|
||||
]
|
||||
starlette = [
|
||||
{file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"},
|
||||
{file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"},
|
||||
@ -2256,12 +1971,6 @@ typing-extensions = [
|
||||
{file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
|
||||
{file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
|
||||
]
|
||||
unify = [
|
||||
{file = "unify-0.5.tar.gz", hash = "sha256:8ddce812b2457212b7598fe574c9e6eb3ad69710f445391338270c7f8a71723c"},
|
||||
]
|
||||
untokenize = [
|
||||
{file = "untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
|
||||
{file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
|
||||
@ -2351,17 +2060,13 @@ werkzeug = [
|
||||
{file = "Werkzeug-2.0.2.tar.gz", hash = "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"},
|
||||
]
|
||||
win32-setctime = [
|
||||
{file = "win32_setctime-1.0.4-py3-none-any.whl", hash = "sha256:7964234073ad9bc7a689ef2ebe6ce931976b644fe73fd50cf7729c996b7d8385"},
|
||||
{file = "win32_setctime-1.0.4.tar.gz", hash = "sha256:2b72b798fdc1d909fb3cc0d25e0be52a42f4848857e3588dd3947c6a18b42609"},
|
||||
{file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"},
|
||||
{file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"},
|
||||
]
|
||||
wsproto = [
|
||||
{file = "wsproto-1.0.0-py3-none-any.whl", hash = "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f"},
|
||||
{file = "wsproto-1.0.0.tar.gz", hash = "sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38"},
|
||||
]
|
||||
yapf = [
|
||||
{file = "yapf-0.32.0-py2.py3-none-any.whl", hash = "sha256:8fea849025584e486fd06d6ba2bed717f396080fd3cc236ba10cb97c4c51cf32"},
|
||||
{file = "yapf-0.32.0.tar.gz", hash = "sha256:a3f5085d37ef7e3e004c4ba9f9b3e40c54ff1901cd111f05145ae313a7c67d1b"},
|
||||
]
|
||||
yarl = [
|
||||
{file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"},
|
||||
{file = "yarl-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da6df107b9ccfe52d3a48165e48d72db0eca3e3029b5b8cb4fe6ee3cb870ba8b"},
|
||||
|
@ -30,21 +30,20 @@ tomlkit = "^0.7.0"
|
||||
fastapi = "^0.70.0"
|
||||
typing-extensions = ">=3.10.0,<5.0.0"
|
||||
Quart = { version = "^0.16.0", optional = true }
|
||||
websockets = { version=">=9.1", optional = true }
|
||||
websockets = { version="^10.0", optional = true }
|
||||
pydantic = { version = "~1.9.0", extras = ["dotenv"] }
|
||||
uvicorn = { version = "^0.15.0", extras = ["standard"] }
|
||||
aiohttp = { version = "^3.7.4", extras = ["speedups"], optional = true }
|
||||
httpx = { version = ">=0.20.0, <1.0.0", extras = ["http2"], optional = true }
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
sphinx = "^4.1.1"
|
||||
isort = "^5.10.1"
|
||||
black = "^21.11b1"
|
||||
pytest-cov = "^3.0.0"
|
||||
pre-commit = "^2.16.0"
|
||||
pytest-xdist = "^2.5.0"
|
||||
nonebug = { git = "https://github.com/nonebot/nonebug.git" }
|
||||
sphinx-markdown-builder = { git = "https://github.com/nonebot/sphinx-markdown-builder.git" }
|
||||
pre-commit = "^2.16.0"
|
||||
nb-autodoc = { git = "https://github.com/nonebot/nb-autodoc.git" }
|
||||
|
||||
[tool.poetry.extras]
|
||||
quart = ["quart"]
|
||||
|
@ -33,7 +33,7 @@ async def _(bot: Bot, event: Event):
|
||||
|
||||
在这段代码中,我们事件响应器指定了 `SUPERUSER` 这样一个权限,那么机器人只会响应超级管理员的 `测试超管` 命令,并且会响应该超级管理员的连续对话。
|
||||
|
||||
::: tip 提示
|
||||
:::tip 提示
|
||||
|
||||
在这里需要强调的是,`Permission` 与 `Rule` 的表现并不相同, `Rule` 只会在初次响应时生效,在余下的对话中并没有限制事件;但是 `Permission` 会持续生效,在连续对话中会一直对事件主体加以限制。
|
||||
|
||||
|
@ -9,7 +9,7 @@ options:
|
||||
|
||||
## 前注
|
||||
|
||||
本章节仅包含插件发布流程指导,插件开发请查阅 **[创建插件](../tutorial/plugin/config-plugin.md)** 章节与 **[Plugin API 文档](../api/plugin.md)** 。
|
||||
本章节仅包含插件发布流程指导,插件开发请查阅 **[创建插件](../tutorial/plugin/introduction.md)** 章节与 **[Plugin API 文档](../api/plugin/index.md)** 。
|
||||
|
||||
## 插件发布流程
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"position": 14
|
||||
"position": 15
|
||||
}
|
||||
|
3
website/docs/api/dependencies/_category_.json
Normal file
3
website/docs/api/dependencies/_category_.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"position": 13
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"position": 13
|
||||
"position": 14
|
||||
}
|
||||
|
3
website/docs/api/plugin/_category_.json
Normal file
3
website/docs/api/plugin/_category_.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"position": 12
|
||||
}
|
Loading…
Reference in New Issue
Block a user