mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-10-31 15:06:42 +00:00 
			
		
		
		
	| @@ -198,6 +198,10 @@ module.exports = context => ({ | |||||||
|                 { |                 { | ||||||
|                   title: "nonebot.adapters.cqhttp 模块", |                   title: "nonebot.adapters.cqhttp 模块", | ||||||
|                   path: "adapters/cqhttp" |                   path: "adapters/cqhttp" | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                   title: "nonebot.adapters.ding 模块", | ||||||
|  |                   path: "adapters/ding" | ||||||
|                 } |                 } | ||||||
|               ] |               ] | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -47,3 +47,6 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
|     * [nonebot.adapters.cqhttp](adapters/cqhttp.html) |     * [nonebot.adapters.cqhttp](adapters/cqhttp.html) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * [nonebot.adapters.ding](adapters/ding.html) | ||||||
|   | |||||||
| @@ -176,7 +176,7 @@ await bot.send_msg(message="hello world") | |||||||
|  |  | ||||||
| ## _class_ `BaseEvent` | ## _class_ `BaseEvent` | ||||||
|  |  | ||||||
| 基类:`abc.ABC` | 基类:`abc.ABC`, `typing.Generic` | ||||||
|  |  | ||||||
| Event 基类。提供上报信息的关键信息,其余信息可从原始上报消息获取。 | Event 基类。提供上报信息的关键信息,其余信息可从原始上报消息获取。 | ||||||
|  |  | ||||||
| @@ -187,7 +187,7 @@ Event 基类。提供上报信息的关键信息,其余信息可从原始上 | |||||||
| * **参数** | * **参数** | ||||||
|  |  | ||||||
|      |      | ||||||
|     * `raw_event: dict`: 原始上报消息 |     * `raw_event: Union[dict, T]`: 原始上报消息 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -309,7 +309,7 @@ Event 基类。提供上报信息的关键信息,其余信息可从原始上 | |||||||
| * **参数** | * **参数** | ||||||
|  |  | ||||||
|      |      | ||||||
|     * `message: Union[str, dict, list, MessageSegment, Message]`: 消息内容 |     * `message: Union[str, dict, list, BaseModel, MessageSegment, Message]`: 消息内容 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -350,7 +350,7 @@ Event 基类。提供上报信息的关键信息,其余信息可从原始上 | |||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
|  |  | ||||||
|     缩减消息数组,即拼接相邻纯文本消息段 |     缩减消息数组,即按 MessageSegment 的实现拼接相邻消息段 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,29 +5,6 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| # NoneBot.adapters.cqhttp 模块 | # NoneBot.adapters.cqhttp 模块 | ||||||
|  |  | ||||||
| ## CQHTTP (OneBot) v11 协议适配 |  | ||||||
|  |  | ||||||
| 协议详情请看: [CQHTTP](https://github.com/howmanybots/onebot/blob/master/README.md) | [OneBot](https://github.com/howmanybots/onebot/blob/master/README.md) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## `log(level, message)` |  | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** |  | ||||||
|  |  | ||||||
|     用于打印 CQHTTP 日志。 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| * **参数** |  | ||||||
|  |  | ||||||
|      |  | ||||||
|     * `level: str`: 日志等级 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     * `message: str`: 日志信息 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## `escape(s, *, escape_comma=True)` | ## `escape(s, *, escape_comma=True)` | ||||||
|  |  | ||||||
| @@ -64,9 +41,50 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## `_b2s(b)` | ## _exception_ `CQHTTPAdapterException` | ||||||
|  |  | ||||||
| 转换布尔值为字符串。 | 基类:[`nonebot.exception.AdapterException`](../exception.md#nonebot.exception.AdapterException) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `ActionFailed` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.ActionFailed`](../exception.md#nonebot.exception.ActionFailed), `nonebot.adapters.cqhttp.exception.CQHTTPAdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     API 请求返回错误信息。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `retcode: Optional[int]`: 错误码 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `NetworkError` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.NetworkError`](../exception.md#nonebot.exception.NetworkError), `nonebot.adapters.cqhttp.exception.CQHTTPAdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     网络错误。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `retcode: Optional[int]`: 错误码 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `ApiNotAvailable` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.cqhttp.exception.CQHTTPAdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
| ## _async_ `_check_reply(bot, event)` | ## _async_ `_check_reply(bot, event)` | ||||||
|   | |||||||
							
								
								
									
										380
									
								
								docs/api/adapters/ding.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								docs/api/adapters/ding.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | |||||||
|  | --- | ||||||
|  | contentSidebar: true | ||||||
|  | sidebarDepth: 0 | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | # NoneBot.adapters.ding 模块 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `DingAdapterException` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.AdapterException`](../exception.md#nonebot.exception.AdapterException) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     钉钉 Adapter 错误基类 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `ActionFailed` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.ActionFailed`](../exception.md#nonebot.exception.ActionFailed), `nonebot.adapters.ding.exception.DingAdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     API 请求返回错误信息。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `errcode: Optional[int]`: 错误码 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `errmsg: Optional[str]`: 错误信息 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `ApiNotAvailable` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.ding.exception.DingAdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `NetworkError` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.NetworkError`](../exception.md#nonebot.exception.NetworkError), `nonebot.adapters.ding.exception.DingAdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     网络错误。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `retcode: Optional[int]`: 错误码 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `SessionExpired` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.ding.exception.DingAdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     发消息的 session 已经过期。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _class_ `Bot` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.adapters.BaseBot`](README.md#nonebot.adapters.BaseBot) | ||||||
|  |  | ||||||
|  | 钉钉 协议 Bot 适配。继承属性参考 [BaseBot](./#class-basebot) 。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `type` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 返回: `"ding"` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _async classmethod_ `check_permission(driver, connection_type, headers, body)` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     钉钉协议鉴权。参考 [鉴权](https://ding-doc.dingtalk.com/doc#/serverapi2/elzz1p) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _async_ `handle_message(body)` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     处理上报消息的函数,转换为 `Event` 事件后调用 `nonebot.message.handle_event` 进一步处理事件。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `message: dict`: 收到的上报消息 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _async_ `call_api(api, event=None, **data)` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     调用 钉钉 协议 API | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `api: str`: API 名称 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `**data: Any`: API 参数 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **返回** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `Any`: API 调用返回数据 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **异常** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `NetworkError`: 网络错误 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `ActionFailed`: API 调用失败 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _async_ `send(event, message, at_sender=False, **kwargs)` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     根据 `event`  向触发事件的主体发送消息。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `event: Event`: Event 对象 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `message: Union[str, Message, MessageSegment]`: 要发送的消息 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `at_sender: bool`: 是否 @ 事件主体 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `**kwargs`: 覆盖默认参数 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **返回** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `Any`: API 调用返回数据 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **异常** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `ValueError`: 缺少 `user_id`, `group_id` | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `NetworkError`: 网络错误 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `ActionFailed`: API 调用失败 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _class_ `Event` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.adapters.BaseEvent`](README.md#nonebot.adapters.BaseEvent) | ||||||
|  |  | ||||||
|  | 钉钉 协议 Event 适配。继承属性参考 [BaseEvent](./#class-baseevent) 。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `raw_event` | ||||||
|  |  | ||||||
|  | 原始上报消息 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `id` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[str]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 消息 ID | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `name` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `str` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 事件名称,由 type.\`detail_type\` 组合而成 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `self_id` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `str` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 机器人自身 ID | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `time` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `int` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 消息的时间戳,单位 s | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `type` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `str` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 事件类型 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `detail_type` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `str` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 事件详细类型 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `sub_type` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `None` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 钉钉适配器无事件子类型 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `user_id` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[str]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 发送者 ID | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `group_id` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[str]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 事件主体群 ID | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `to_me` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[bool]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 消息是否与机器人相关 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `message` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[Message]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 消息内容 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `reply` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `None` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 回复消息详情 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `raw_message` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[str]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 原始消息 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `plain_text` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[str]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 纯文本消息内容 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _property_ `sender` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 类型: `Optional[dict]` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * 说明: 消息发送者信息 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _class_ `MessageSegment` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.adapters.BaseMessageSegment`](README.md#nonebot.adapters.BaseMessageSegment) | ||||||
|  |  | ||||||
|  | 钉钉 协议 MessageSegment 适配。具体方法参考协议消息段类型或源码。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _static_ `actionCardSingleMultiBtns(title, text, btns=[], hideAvatar=False, btnOrientation='1')` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `btnOrientation`: 0:按钮竖直排列 1:按钮横向排列 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     * `btns`: [{ "title": title, "actionURL": actionURL }, ...] | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _static_ `feedCard(links=[])` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `links`: [{ "title": xxx, "messageURL": xxx, "picURL": xxx }, ...] | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### _static_ `empty()` | ||||||
|  |  | ||||||
|  | 不想回复消息到群里 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _class_ `Message` | ||||||
|  |  | ||||||
|  | 基类:[`nonebot.adapters.BaseMessage`](README.md#nonebot.adapters.BaseMessage) | ||||||
|  |  | ||||||
|  | 钉钉 协议 Message 适配。 | ||||||
| @@ -11,11 +11,22 @@ sidebarDepth: 0 | |||||||
| 这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 | 这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 | ||||||
|  |  | ||||||
|  |  | ||||||
| ## _exception_ `IgnoredException` | ## _exception_ `NoneBotException` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`Exception` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     所有 NoneBot 发生的异常基类。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `IgnoredException` | ||||||
|  |  | ||||||
|  | 基类:`nonebot.exception.NoneBotException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
|  |  | ||||||
|     指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。 |     指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。 | ||||||
| @@ -31,7 +42,7 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _exception_ `PausedException` | ## _exception_ `PausedException` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.NoneBotException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
| @@ -49,7 +60,7 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _exception_ `RejectedException` | ## _exception_ `RejectedException` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.NoneBotException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
| @@ -67,7 +78,7 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _exception_ `FinishedException` | ## _exception_ `FinishedException` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.NoneBotException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
| @@ -85,7 +96,7 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _exception_ `StopPropagation` | ## _exception_ `StopPropagation` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.NoneBotException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
| @@ -102,7 +113,7 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _exception_ `RequestDenied` | ## _exception_ `RequestDenied` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.NoneBotException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
| @@ -121,9 +132,27 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## _exception_ `AdapterException` | ||||||
|  |  | ||||||
|  | 基类:`nonebot.exception.NoneBotException` | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **说明** | ||||||
|  |  | ||||||
|  |     代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception` | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | * **参数** | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     * `adapter_name: str`: 标识 adapter | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## _exception_ `ApiNotAvailable` | ## _exception_ `ApiNotAvailable` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.AdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
| @@ -134,7 +163,7 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _exception_ `NetworkError` | ## _exception_ `NetworkError` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.AdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
| @@ -145,16 +174,9 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _exception_ `ActionFailed` | ## _exception_ `ActionFailed` | ||||||
|  |  | ||||||
| 基类:`Exception` | 基类:`nonebot.exception.AdapterException` | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
|  |  | ||||||
|     API 请求成功返回数据,但 API 操作失败。 |     API 请求成功返回数据,但 API 操作失败。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| * **参数** |  | ||||||
|  |  | ||||||
|      |  | ||||||
|     * `retcode: Optional[int]`: 错误代码 |  | ||||||
|   | |||||||
| @@ -54,8 +54,6 @@ sidebarDepth: 0 | |||||||
|  |  | ||||||
| ## _class_ `DataclassEncoder` | ## _class_ `DataclassEncoder` | ||||||
|  |  | ||||||
| 基类:`json.encoder.JSONEncoder` |  | ||||||
|  |  | ||||||
|  |  | ||||||
| * **说明** | * **说明** | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,3 +17,4 @@ NoneBot Api Reference | |||||||
|   - `nonebot.drivers.fastapi <drivers/fastapi.html>`_ |   - `nonebot.drivers.fastapi <drivers/fastapi.html>`_ | ||||||
|   - `nonebot.adapters <adapters/>`_ |   - `nonebot.adapters <adapters/>`_ | ||||||
|   - `nonebot.adapters.cqhttp <adapters/cqhttp.html>`_ |   - `nonebot.adapters.cqhttp <adapters/cqhttp.html>`_ | ||||||
|  |   - `nonebot.adapters.ding <adapters/ding.html>`_ | ||||||
|   | |||||||
| @@ -6,7 +6,28 @@ sidebarDepth: 0 | |||||||
| NoneBot.adapters.cqhttp 模块 | NoneBot.adapters.cqhttp 模块 | ||||||
| ============================ | ============================ | ||||||
|  |  | ||||||
| .. automodule:: nonebot.adapters.cqhttp | .. automodule:: nonebot.adapters.cqhttp.utils | ||||||
|  |    :members: | ||||||
|  |    :show-inheritance: | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.cqhttp.exception | ||||||
|  |    :members: | ||||||
|  |    :show-inheritance: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.cqhttp.bot | ||||||
|  |    :members: | ||||||
|  |    :private-members: | ||||||
|  |    :show-inheritance: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.cqhttp.event | ||||||
|  |    :members: | ||||||
|  |    :private-members: | ||||||
|  |    :show-inheritance: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.cqhttp.message | ||||||
|    :members: |    :members: | ||||||
|    :private-members: |    :private-members: | ||||||
|    :show-inheritance: |    :show-inheritance: | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								docs_build/adapters/ding.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								docs_build/adapters/ding.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | --- | ||||||
|  | contentSidebar: true | ||||||
|  | sidebarDepth: 0 | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | NoneBot.adapters.ding 模块 | ||||||
|  | ============================ | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.ding.exception | ||||||
|  |    :members: | ||||||
|  |    :show-inheritance: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.ding.bot | ||||||
|  |    :members: | ||||||
|  |    :private-members: | ||||||
|  |    :show-inheritance: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.ding.event | ||||||
|  |    :members: | ||||||
|  |    :private-members: | ||||||
|  |    :show-inheritance: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .. automodule:: nonebot.adapters.ding.message | ||||||
|  |    :members: | ||||||
|  |    :private-members: | ||||||
|  |    :show-inheritance: | ||||||
| @@ -10,4 +10,5 @@ NoneBot.utils 模块 | |||||||
| .. autofunction:: nonebot.utils.escape_tag | .. autofunction:: nonebot.utils.escape_tag | ||||||
| .. autodecorator:: nonebot.utils.run_sync | .. autodecorator:: nonebot.utils.run_sync | ||||||
| .. autoclass:: nonebot.utils.DataclassEncoder | .. autoclass:: nonebot.utils.DataclassEncoder | ||||||
|  | .. autodecorator:: nonebot.utils.logger_wrapper | ||||||
|   :show-inheritance: |   :show-inheritance: | ||||||
|   | |||||||
| @@ -9,9 +9,11 @@ import abc | |||||||
| from functools import reduce, partial | from functools import reduce, partial | ||||||
| from dataclasses import dataclass, field | from dataclasses import dataclass, field | ||||||
|  |  | ||||||
|  | from pydantic import BaseModel | ||||||
|  |  | ||||||
| from nonebot.config import Config | from nonebot.config import Config | ||||||
| from nonebot.typing import Driver, Message, WebSocket | from nonebot.typing import Driver, Message, WebSocket | ||||||
| from nonebot.typing import Any, Dict, Union, Optional, NoReturn, Callable, Iterable, Awaitable | from nonebot.typing import Any, Dict, Union, Optional, NoReturn, Callable, Iterable, Awaitable, TypeVar, Generic | ||||||
|  |  | ||||||
|  |  | ||||||
| class BaseBot(abc.ABC): | class BaseBot(abc.ABC): | ||||||
| @@ -135,16 +137,19 @@ class BaseBot(abc.ABC): | |||||||
|         raise NotImplementedError |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |  | ||||||
| class BaseEvent(abc.ABC): | T = TypeVar("T", bound=BaseModel) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class BaseEvent(abc.ABC, Generic[T]): | ||||||
|     """ |     """ | ||||||
|     Event 基类。提供上报信息的关键信息,其余信息可从原始上报消息获取。 |     Event 基类。提供上报信息的关键信息,其余信息可从原始上报消息获取。 | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, raw_event: dict): |     def __init__(self, raw_event: Union[dict, T]): | ||||||
|         """ |         """ | ||||||
|         :参数: |         :参数: | ||||||
|  |  | ||||||
|           * ``raw_event: dict``: 原始上报消息 |           * ``raw_event: Union[dict, T]``: 原始上报消息 | ||||||
|         """ |         """ | ||||||
|         self._raw_event = raw_event |         self._raw_event = raw_event | ||||||
|  |  | ||||||
| @@ -152,7 +157,7 @@ class BaseEvent(abc.ABC): | |||||||
|         return f"<Event {self.self_id}: {self.name} {self.time}>" |         return f"<Event {self.self_id}: {self.name} {self.time}>" | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def raw_event(self) -> dict: |     def raw_event(self) -> Union[dict, T]: | ||||||
|         """原始上报消息""" |         """原始上报消息""" | ||||||
|         return self._raw_event |         return self._raw_event | ||||||
|  |  | ||||||
| @@ -347,17 +352,17 @@ class BaseMessage(list, abc.ABC): | |||||||
|     """消息数组""" |     """消息数组""" | ||||||
|  |  | ||||||
|     def __init__(self, |     def __init__(self, | ||||||
|                  message: Union[str, dict, list, BaseMessageSegment, |                  message: Union[str, dict, list, BaseModel, BaseMessageSegment, | ||||||
|                                 "BaseMessage"] = None, |                                 "BaseMessage"] = None, | ||||||
|                  *args, |                  *args, | ||||||
|                  **kwargs): |                  **kwargs): | ||||||
|         """ |         """ | ||||||
|         :参数: |         :参数: | ||||||
|  |  | ||||||
|           * ``message: Union[str, dict, list, MessageSegment, Message]``: 消息内容 |           * ``message: Union[str, dict, list, BaseModel, MessageSegment, Message]``: 消息内容 | ||||||
|         """ |         """ | ||||||
|         super().__init__(*args, **kwargs) |         super().__init__(*args, **kwargs) | ||||||
|         if isinstance(message, (str, dict, list)): |         if isinstance(message, (str, dict, list, BaseModel)): | ||||||
|             self.extend(self._construct(message)) |             self.extend(self._construct(message)) | ||||||
|         elif isinstance(message, BaseMessage): |         elif isinstance(message, BaseMessage): | ||||||
|             self.extend(message) |             self.extend(message) | ||||||
|   | |||||||
| @@ -10,6 +10,8 @@ CQHTTP (OneBot) v11 协议适配 | |||||||
|     https://github.com/howmanybots/onebot/blob/master/README.md |     https://github.com/howmanybots/onebot/blob/master/README.md | ||||||
| """ | """ | ||||||
|  |  | ||||||
| from .message import Message, MessageSegment |  | ||||||
| from .bot import Bot |  | ||||||
| from .event import Event | from .event import Event | ||||||
|  | from .message import Message, MessageSegment | ||||||
|  | from .utils import log, escape, unescape, _b2s | ||||||
|  | from .bot import Bot, _check_at_me, _check_nickname, _check_reply, _handle_api_result | ||||||
|  | from .exception import CQHTTPAdapterException, ApiNotAvailable, ActionFailed, NetworkError | ||||||
|   | |||||||
| @@ -8,15 +8,26 @@ import httpx | |||||||
|  |  | ||||||
| from nonebot.log import logger | from nonebot.log import logger | ||||||
| from nonebot.config import Config | from nonebot.config import Config | ||||||
| from nonebot.message import handle_event |  | ||||||
| from nonebot.typing import overrides, Driver, WebSocket, NoReturn |  | ||||||
| from nonebot.typing import Any, Dict, Union, Optional |  | ||||||
| from nonebot.adapters import BaseBot | from nonebot.adapters import BaseBot | ||||||
| from nonebot.exception import NetworkError, ActionFailed, RequestDenied, ApiNotAvailable | from nonebot.message import handle_event | ||||||
|  | from nonebot.exception import RequestDenied | ||||||
|  | from nonebot.typing import Any, Dict, Union, Optional | ||||||
|  | from nonebot.typing import overrides, Driver, WebSocket, NoReturn | ||||||
|  |  | ||||||
| from .message import Message, MessageSegment |  | ||||||
| from .utils import log, get_auth_bearer |  | ||||||
| from .event import Event | from .event import Event | ||||||
|  | from .message import Message, MessageSegment | ||||||
|  | from .exception import NetworkError, ApiNotAvailable, ActionFailed | ||||||
|  | from .utils import log | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_auth_bearer( | ||||||
|  |         access_token: Optional[str] = None) -> Union[Optional[str], NoReturn]: | ||||||
|  |     if not access_token: | ||||||
|  |         return None | ||||||
|  |     scheme, _, param = access_token.partition(" ") | ||||||
|  |     if scheme.lower() not in ["bearer", "token"]: | ||||||
|  |         raise RequestDenied(401, "Not authenticated") | ||||||
|  |     return param | ||||||
|  |  | ||||||
|  |  | ||||||
| async def _check_reply(bot: "Bot", event: "Event"): | async def _check_reply(bot: "Bot", event: "Event"): | ||||||
| @@ -236,7 +247,7 @@ class Bot(BaseBot): | |||||||
|         """ |         """ | ||||||
|         x_self_id = headers.get("x-self-id") |         x_self_id = headers.get("x-self-id") | ||||||
|         x_signature = headers.get("x-signature") |         x_signature = headers.get("x-signature") | ||||||
|         access_token = get_auth_bearer(headers.get("authorization")) |         token = get_auth_bearer(headers.get("authorization")) | ||||||
|  |  | ||||||
|         # 检查连接方式 |         # 检查连接方式 | ||||||
|         if connection_type not in ["http", "websocket"]: |         if connection_type not in ["http", "websocket"]: | ||||||
| @@ -261,13 +272,13 @@ class Bot(BaseBot): | |||||||
|                 raise RequestDenied(403, "Signature is invalid") |                 raise RequestDenied(403, "Signature is invalid") | ||||||
|  |  | ||||||
|         access_token = driver.config.access_token |         access_token = driver.config.access_token | ||||||
|         if access_token and access_token != access_token: |         if access_token and access_token != token: | ||||||
|             log( |             log( | ||||||
|                 "WARNING", "Authorization Header is invalid" |                 "WARNING", "Authorization Header is invalid" | ||||||
|                 if access_token else "Missing Authorization Header") |                 if token else "Missing Authorization Header") | ||||||
|             raise RequestDenied( |             raise RequestDenied( | ||||||
|                 403, "Authorization Header is invalid" |                 403, "Authorization Header is invalid" | ||||||
|                 if access_token else "Missing Authorization Header") |                 if token else "Missing Authorization Header") | ||||||
|         return str(x_self_id) |         return str(x_self_id) | ||||||
|  |  | ||||||
|     @overrides(BaseBot) |     @overrides(BaseBot) | ||||||
| @@ -368,8 +379,8 @@ class Bot(BaseBot): | |||||||
|  |  | ||||||
|     @overrides(BaseBot) |     @overrides(BaseBot) | ||||||
|     async def send(self, |     async def send(self, | ||||||
|                    event: "Event", |                    event: Event, | ||||||
|                    message: Union[str, "Message", "MessageSegment"], |                    message: Union[str, Message, MessageSegment], | ||||||
|                    at_sender: bool = False, |                    at_sender: bool = False, | ||||||
|                    **kwargs) -> Union[Any, NoReturn]: |                    **kwargs) -> Union[Any, NoReturn]: | ||||||
|         """ |         """ | ||||||
|   | |||||||
| @@ -1,12 +1,11 @@ | |||||||
| import asyncio | import asyncio | ||||||
| 
 | 
 | ||||||
| from nonebot.config import Config | from nonebot.config import Config | ||||||
| from nonebot.adapters import BaseBot, BaseEvent, BaseMessage, BaseMessageSegment | from nonebot.adapters import BaseBot | ||||||
| from nonebot.typing import Any, Dict, List, Union, Driver, Optional, NoReturn, WebSocket, Iterable | from nonebot.typing import Any, Dict, List, Union, Driver, Optional, NoReturn, WebSocket | ||||||
| 
 | 
 | ||||||
| 
 | from .event import Event | ||||||
| def log(level: str, message: str): | from .message import Message, MessageSegment | ||||||
|     ... |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_auth_bearer( | def get_auth_bearer( | ||||||
| @@ -14,27 +13,15 @@ def get_auth_bearer( | |||||||
|     ... |     ... | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def escape(s: str, *, escape_comma: bool = ...) -> str: | async def _check_reply(bot: "Bot", event: Event): | ||||||
|     ... |     ... | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def unescape(s: str) -> str: | def _check_at_me(bot: "Bot", event: Event): | ||||||
|     ... |     ... | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _b2s(b: Optional[bool]) -> Optional[str]: | def _check_nickname(bot: "Bot", event: Event): | ||||||
|     ... |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| async def _check_reply(bot: "Bot", event: "Event"): |  | ||||||
|     ... |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _check_at_me(bot: "Bot", event: "Event"): |  | ||||||
|     ... |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _check_nickname(bot: "Bot", event: "Event"): |  | ||||||
|     ... |     ... | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -86,8 +73,8 @@ class Bot(BaseBot): | |||||||
|     async def call_api(self, api: str, **data) -> Union[Any, NoReturn]: |     async def call_api(self, api: str, **data) -> Union[Any, NoReturn]: | ||||||
|         ... |         ... | ||||||
| 
 | 
 | ||||||
|     async def send(self, event: "Event", message: Union[str, "Message", |     async def send(self, event: Event, message: Union[str, Message, | ||||||
|                                                         "MessageSegment"], |                                                       MessageSegment], | ||||||
|                    **kwargs) -> Union[Any, NoReturn]: |                    **kwargs) -> Union[Any, NoReturn]: | ||||||
|         ... |         ... | ||||||
| 
 | 
 | ||||||
| @@ -759,242 +746,3 @@ class Bot(BaseBot): | |||||||
|           * ``self_id``: 机器人 QQ 号 |           * ``self_id``: 机器人 QQ 号 | ||||||
|         """ |         """ | ||||||
|         ... |         ... | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Event(BaseEvent): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, raw_event: dict): |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def id(self) -> Optional[int]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def name(self) -> str: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def self_id(self) -> str: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def time(self) -> int: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def type(self) -> str: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @type.setter |  | ||||||
|     def type(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def detail_type(self) -> str: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @detail_type.setter |  | ||||||
|     def detail_type(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def sub_type(self) -> Optional[str]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @sub_type.setter |  | ||||||
|     def sub_type(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def user_id(self) -> Optional[int]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @user_id.setter |  | ||||||
|     def user_id(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def group_id(self) -> Optional[int]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @group_id.setter |  | ||||||
|     def group_id(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def to_me(self) -> Optional[bool]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @to_me.setter |  | ||||||
|     def to_me(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def message(self) -> Optional["Message"]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @message.setter |  | ||||||
|     def message(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def reply(self) -> Optional[dict]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @reply.setter |  | ||||||
|     def reply(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def raw_message(self) -> Optional[str]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @raw_message.setter |  | ||||||
|     def raw_message(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def plain_text(self) -> Optional[str]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def sender(self) -> Optional[dict]: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @sender.setter |  | ||||||
|     def sender(self, value) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class MessageSegment(BaseMessageSegment): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, type: str, data: Dict[str, Any]) -> None: |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     def __add__(self, other) -> "Message": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def anonymous(ignore_failure: Optional[bool] = ...) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def at(user_id: Union[int, str]) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def contact_group(group_id: int) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def contact_user(user_id: int) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def dice() -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def face(id_: int) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def forward(id_: str) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def image(file: str, |  | ||||||
|               type_: Optional[str] = ..., |  | ||||||
|               cache: bool = ..., |  | ||||||
|               proxy: bool = ..., |  | ||||||
|               timeout: Optional[int] = ...) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def json(data: str) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def location(latitude: float, |  | ||||||
|                  longitude: float, |  | ||||||
|                  title: Optional[str] = ..., |  | ||||||
|                  content: Optional[str] = ...) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def music(type_: str, id_: int) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def music_custom(url: str, |  | ||||||
|                      audio: str, |  | ||||||
|                      title: str, |  | ||||||
|                      content: Optional[str] = ..., |  | ||||||
|                      img_url: Optional[str] = ...) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def node(id_: int) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def node_custom(user_id: int, nickname: str, |  | ||||||
|                     content: Union[str, "Message"]) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def poke(type_: str, id_: str) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def record(file: str, |  | ||||||
|                magic: Optional[bool] = ..., |  | ||||||
|                cache: Optional[bool] = ..., |  | ||||||
|                proxy: Optional[bool] = ..., |  | ||||||
|                timeout: Optional[int] = ...) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def reply(id_: int) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def rps() -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def shake() -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def share(url: str = ..., |  | ||||||
|               title: str = ..., |  | ||||||
|               content: Optional[str] = ..., |  | ||||||
|               img_url: Optional[str] = ...) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def text(text: str) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def video(file: str, |  | ||||||
|               cache: Optional[bool] = ..., |  | ||||||
|               proxy: Optional[bool] = ..., |  | ||||||
|               timeout: Optional[int] = ...) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def xml(data: str) -> "MessageSegment": |  | ||||||
|         ... |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Message(BaseMessage): |  | ||||||
| 
 |  | ||||||
|     @staticmethod |  | ||||||
|     def _construct(msg: Union[str, dict, list]) -> Iterable[MessageSegment]: |  | ||||||
|         ... |  | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| from nonebot.typing import overrides |  | ||||||
| from nonebot.typing import Optional |  | ||||||
| from nonebot.adapters import BaseEvent | from nonebot.adapters import BaseEvent | ||||||
|  | from nonebot.typing import Optional, overrides | ||||||
|  |  | ||||||
| from .message import Message | from .message import Message | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										59
									
								
								nonebot/adapters/cqhttp/exception.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								nonebot/adapters/cqhttp/exception.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | from nonebot.typing import Optional | ||||||
|  | from nonebot.exception import (AdapterException, ActionFailed as | ||||||
|  |                                BaseActionFailed, NetworkError as | ||||||
|  |                                BaseNetworkError, ApiNotAvailable as | ||||||
|  |                                BaseApiNotAvailable) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CQHTTPAdapterException(AdapterException): | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         super().__init__("cqhttp") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ActionFailed(BaseActionFailed, CQHTTPAdapterException): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       API 请求返回错误信息。 | ||||||
|  |  | ||||||
|  |     :参数: | ||||||
|  |  | ||||||
|  |       * ``retcode: Optional[int]``: 错误码 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, retcode: Optional[int] = None): | ||||||
|  |         super().__init__() | ||||||
|  |         self.retcode = retcode | ||||||
|  |  | ||||||
|  |     def __repr__(self): | ||||||
|  |         return f"<ActionFailed retcode={self.retcode}>" | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.__repr__() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class NetworkError(BaseNetworkError, CQHTTPAdapterException): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       网络错误。 | ||||||
|  |  | ||||||
|  |     :参数: | ||||||
|  |  | ||||||
|  |       * ``retcode: Optional[int]``: 错误码 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, msg: Optional[str] = None): | ||||||
|  |         super().__init__() | ||||||
|  |         self.msg = msg | ||||||
|  |  | ||||||
|  |     def __repr__(self): | ||||||
|  |         return f"<NetWorkError message={self.msg}>" | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.__repr__() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ApiNotAvailable(BaseApiNotAvailable, CQHTTPAdapterException): | ||||||
|  |     pass | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| import re | import re | ||||||
|  |  | ||||||
| from nonebot.typing import overrides | from nonebot.typing import Any, Dict, Union, Tuple, Iterable, Optional, overrides | ||||||
| from nonebot.typing import Any, Dict, Union, Tuple, Iterable, Optional |  | ||||||
| from nonebot.adapters import BaseMessage, BaseMessageSegment | from nonebot.adapters import BaseMessage, BaseMessageSegment | ||||||
|  |  | ||||||
| from .utils import log, escape, unescape, _b2s | from .utils import log, escape, unescape, _b2s | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,21 +1,9 @@ | |||||||
| from nonebot.typing import NoReturn | from nonebot.typing import Optional | ||||||
| from nonebot.typing import Union, Optional |  | ||||||
| from nonebot.exception import RequestDenied |  | ||||||
| from nonebot.utils import logger_wrapper | from nonebot.utils import logger_wrapper | ||||||
|  |  | ||||||
| log = logger_wrapper("CQHTTP") | log = logger_wrapper("CQHTTP") | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_auth_bearer( |  | ||||||
|         access_token: Optional[str] = None) -> Union[Optional[str], NoReturn]: |  | ||||||
|     if not access_token: |  | ||||||
|         return None |  | ||||||
|     scheme, _, param = access_token.partition(" ") |  | ||||||
|     if scheme.lower() not in ["bearer", "token"]: |  | ||||||
|         raise RequestDenied(401, "Not authenticated") |  | ||||||
|     return param |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def escape(s: str, *, escape_comma: bool = True) -> str: | def escape(s: str, *, escape_comma: bool = True) -> str: | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								nonebot/adapters/ding/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								nonebot/adapters/ding/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | """ | ||||||
|  | 钉钉群机器人 协议适配 | ||||||
|  | ============================ | ||||||
|  |  | ||||||
|  | 协议详情请看: `钉钉文档`_ | ||||||
|  |  | ||||||
|  | .. _钉钉文档: | ||||||
|  |     https://ding-doc.dingtalk.com/doc#/serverapi2/krgddi | ||||||
|  |  | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | from .utils import log | ||||||
|  | from .bot import Bot | ||||||
|  | from .event import Event | ||||||
|  | from .message import Message, MessageSegment | ||||||
|  | from .exception import (DingAdapterException, ApiNotAvailable, NetworkError, | ||||||
|  |                         ActionFailed, SessionExpired) | ||||||
							
								
								
									
										197
									
								
								nonebot/adapters/ding/bot.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								nonebot/adapters/ding/bot.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,197 @@ | |||||||
|  | import hmac | ||||||
|  | import base64 | ||||||
|  | from datetime import datetime | ||||||
|  |  | ||||||
|  | import httpx | ||||||
|  | from nonebot.log import logger | ||||||
|  | from nonebot.config import Config | ||||||
|  | from nonebot.adapters import BaseBot | ||||||
|  | from nonebot.message import handle_event | ||||||
|  | from nonebot.exception import RequestDenied | ||||||
|  | from nonebot.typing import Any, Union, Driver, Optional, NoReturn | ||||||
|  |  | ||||||
|  | from .utils import log | ||||||
|  | from .event import Event | ||||||
|  | from .model import MessageModel | ||||||
|  | from .message import Message, MessageSegment | ||||||
|  | from .exception import NetworkError, ApiNotAvailable, ActionFailed, SessionExpired | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Bot(BaseBot): | ||||||
|  |     """ | ||||||
|  |     钉钉 协议 Bot 适配。继承属性参考 `BaseBot <./#class-basebot>`_ 。 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, driver: Driver, connection_type: str, config: Config, | ||||||
|  |                  self_id: str, **kwargs): | ||||||
|  |  | ||||||
|  |         super().__init__(driver, connection_type, config, self_id, **kwargs) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def type(self) -> str: | ||||||
|  |         """ | ||||||
|  |         - 返回: ``"ding"`` | ||||||
|  |         """ | ||||||
|  |         return "ding" | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     async def check_permission(cls, driver: Driver, connection_type: str, | ||||||
|  |                                headers: dict, body: Optional[dict]) -> str: | ||||||
|  |         """ | ||||||
|  |         :说明: | ||||||
|  |  | ||||||
|  |           钉钉协议鉴权。参考 `鉴权 <https://ding-doc.dingtalk.com/doc#/serverapi2/elzz1p>`_ | ||||||
|  |         """ | ||||||
|  |         timestamp = headers.get("timestamp") | ||||||
|  |         sign = headers.get("sign") | ||||||
|  |  | ||||||
|  |         # 检查连接方式 | ||||||
|  |         if connection_type not in ["http"]: | ||||||
|  |             raise RequestDenied(405, "Unsupported connection type") | ||||||
|  |  | ||||||
|  |         # 检查 timestamp | ||||||
|  |         if not timestamp: | ||||||
|  |             raise RequestDenied(400, "Missing `timestamp` Header") | ||||||
|  |  | ||||||
|  |         # 检查 sign | ||||||
|  |         secret = driver.config.secret | ||||||
|  |         if secret: | ||||||
|  |             if not sign: | ||||||
|  |                 log("WARNING", "Missing Signature Header") | ||||||
|  |                 raise RequestDenied(400, "Missing `sign` Header") | ||||||
|  |             string_to_sign = f"{timestamp}\n{secret}" | ||||||
|  |             sig = hmac.new(secret.encode("utf-8"), | ||||||
|  |                            string_to_sign.encode("utf-8"), "sha256").digest() | ||||||
|  |             if sign != base64.b64encode(sig).decode("utf-8"): | ||||||
|  |                 log("WARNING", "Signature Header is invalid") | ||||||
|  |                 raise RequestDenied(403, "Signature is invalid") | ||||||
|  |         else: | ||||||
|  |             log("WARNING", "Ding signature check ignored!") | ||||||
|  |         return body["chatbotUserId"] | ||||||
|  |  | ||||||
|  |     async def handle_message(self, body: dict): | ||||||
|  |         message = MessageModel.parse_obj(body) | ||||||
|  |         if not message: | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             event = Event(message) | ||||||
|  |             await handle_event(self, event) | ||||||
|  |         except Exception as e: | ||||||
|  |             logger.opt(colors=True, exception=e).error( | ||||||
|  |                 f"<r><bg #f8bbd0>Failed to handle event. Raw: {message}</bg #f8bbd0></r>" | ||||||
|  |             ) | ||||||
|  |         return | ||||||
|  |  | ||||||
|  |     async def call_api(self, | ||||||
|  |                        api: str, | ||||||
|  |                        event: Optional[Event] = None, | ||||||
|  |                        **data) -> Union[Any, NoReturn]: | ||||||
|  |         """ | ||||||
|  |         :说明: | ||||||
|  |  | ||||||
|  |           调用 钉钉 协议 API | ||||||
|  |  | ||||||
|  |         :参数: | ||||||
|  |  | ||||||
|  |           * ``api: str``: API 名称 | ||||||
|  |           * ``**data: Any``: API 参数 | ||||||
|  |  | ||||||
|  |         :返回: | ||||||
|  |  | ||||||
|  |           - ``Any``: API 调用返回数据 | ||||||
|  |  | ||||||
|  |         :异常: | ||||||
|  |  | ||||||
|  |           - ``NetworkError``: 网络错误 | ||||||
|  |           - ``ActionFailed``: API 调用失败 | ||||||
|  |         """ | ||||||
|  |         if self.connection_type != "http": | ||||||
|  |             log("ERROR", "Only support http connection.") | ||||||
|  |             return | ||||||
|  |         if "self_id" in data: | ||||||
|  |             self_id = data.pop("self_id") | ||||||
|  |             if self_id: | ||||||
|  |                 bot = self.driver.bots[str(self_id)] | ||||||
|  |                 return await bot.call_api(api, **data) | ||||||
|  |  | ||||||
|  |         log("DEBUG", f"Calling API <y>{api}</y>") | ||||||
|  |  | ||||||
|  |         if api == "send_message": | ||||||
|  |             if event: | ||||||
|  |                 # 确保 sessionWebhook 没有过期 | ||||||
|  |                 if int(datetime.now().timestamp()) > int( | ||||||
|  |                         event.raw_event.sessionWebhookExpiredTime / 1000): | ||||||
|  |                     raise SessionExpired | ||||||
|  |  | ||||||
|  |                 target = event.raw_event.sessionWebhook | ||||||
|  |             else: | ||||||
|  |                 target = None | ||||||
|  |  | ||||||
|  |             if not target: | ||||||
|  |                 raise ApiNotAvailable | ||||||
|  |  | ||||||
|  |             headers = {} | ||||||
|  |             segment: MessageSegment = data["message"][0] | ||||||
|  |             try: | ||||||
|  |                 async with httpx.AsyncClient(headers=headers) as client: | ||||||
|  |                     response = await client.post( | ||||||
|  |                         target, | ||||||
|  |                         params={"access_token": self.config.access_token}, | ||||||
|  |                         json=segment.data, | ||||||
|  |                         timeout=self.config.api_timeout) | ||||||
|  |  | ||||||
|  |                 if 200 <= response.status_code < 300: | ||||||
|  |                     result = response.json() | ||||||
|  |                     if isinstance(result, dict): | ||||||
|  |                         if result.get("errcode") != 0: | ||||||
|  |                             raise ActionFailed(errcode=result.get("errcode"), | ||||||
|  |                                                errmsg=result.get("errmsg")) | ||||||
|  |                         return result | ||||||
|  |                 raise NetworkError(f"HTTP request received unexpected " | ||||||
|  |                                    f"status code: {response.status_code}") | ||||||
|  |             except httpx.InvalidURL: | ||||||
|  |                 raise NetworkError("API root url invalid") | ||||||
|  |             except httpx.HTTPError: | ||||||
|  |                 raise NetworkError("HTTP request failed") | ||||||
|  |  | ||||||
|  |     async def send(self, | ||||||
|  |                    event: Event, | ||||||
|  |                    message: Union[str, "Message", "MessageSegment"], | ||||||
|  |                    at_sender: bool = False, | ||||||
|  |                    **kwargs) -> Union[Any, NoReturn]: | ||||||
|  |         """ | ||||||
|  |         :说明: | ||||||
|  |  | ||||||
|  |           根据 ``event``  向触发事件的主体发送消息。 | ||||||
|  |  | ||||||
|  |         :参数: | ||||||
|  |  | ||||||
|  |           * ``event: Event``: Event 对象 | ||||||
|  |           * ``message: Union[str, Message, MessageSegment]``: 要发送的消息 | ||||||
|  |           * ``at_sender: bool``: 是否 @ 事件主体 | ||||||
|  |           * ``**kwargs``: 覆盖默认参数 | ||||||
|  |  | ||||||
|  |         :返回: | ||||||
|  |  | ||||||
|  |           - ``Any``: API 调用返回数据 | ||||||
|  |  | ||||||
|  |         :异常: | ||||||
|  |  | ||||||
|  |           - ``ValueError``: 缺少 ``user_id``, ``group_id`` | ||||||
|  |           - ``NetworkError``: 网络错误 | ||||||
|  |           - ``ActionFailed``: API 调用失败 | ||||||
|  |         """ | ||||||
|  |         msg = message if isinstance(message, Message) else Message(message) | ||||||
|  |  | ||||||
|  |         at_sender = at_sender and bool(event.user_id) | ||||||
|  |         params = {} | ||||||
|  |         params["event"] = event | ||||||
|  |         params.update(kwargs) | ||||||
|  |  | ||||||
|  |         if at_sender and event.detail_type != "private": | ||||||
|  |             params["message"] = f"@{event.user_id} " + msg | ||||||
|  |         else: | ||||||
|  |             params["message"] = msg | ||||||
|  |  | ||||||
|  |         return await self.call_api("send_message", **params) | ||||||
							
								
								
									
										196
									
								
								nonebot/adapters/ding/event.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								nonebot/adapters/ding/event.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,196 @@ | |||||||
|  | from nonebot.adapters import BaseEvent | ||||||
|  | from nonebot.typing import Union, Optional | ||||||
|  |  | ||||||
|  | from .message import Message | ||||||
|  | from .model import MessageModel, ConversationType, TextMessage | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Event(BaseEvent): | ||||||
|  |     """ | ||||||
|  |     钉钉 协议 Event 适配。继承属性参考 `BaseEvent <./#class-baseevent>`_ 。 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, message: MessageModel): | ||||||
|  |         super().__init__(message) | ||||||
|  |         # 其实目前钉钉机器人只能接收到 text 类型的消息 | ||||||
|  |         self._message = Message(getattr(message, message.msgtype or "text")) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def raw_event(self) -> MessageModel: | ||||||
|  |         """原始上报消息""" | ||||||
|  |         return self._raw_event | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def id(self) -> Optional[str]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[str]`` | ||||||
|  |         - 说明: 消息 ID | ||||||
|  |         """ | ||||||
|  |         return self.raw_event.msgId | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def name(self) -> str: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``str`` | ||||||
|  |         - 说明: 事件名称,由 `type`.`detail_type` 组合而成 | ||||||
|  |         """ | ||||||
|  |         return self.type + "." + self.detail_type | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def self_id(self) -> str: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``str`` | ||||||
|  |         - 说明: 机器人自身 ID | ||||||
|  |         """ | ||||||
|  |         return str(self.raw_event.chatbotUserId) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def time(self) -> int: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``int`` | ||||||
|  |         - 说明: 消息的时间戳,单位 s | ||||||
|  |         """ | ||||||
|  |         # 单位 ms -> s | ||||||
|  |         return int(self.raw_event.createAt / 1000) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def type(self) -> str: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``str`` | ||||||
|  |         - 说明: 事件类型 | ||||||
|  |         """ | ||||||
|  |         return "message" | ||||||
|  |  | ||||||
|  |     @type.setter | ||||||
|  |     def type(self, value) -> None: | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def detail_type(self) -> str: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``str`` | ||||||
|  |         - 说明: 事件详细类型 | ||||||
|  |         """ | ||||||
|  |         return self.raw_event.conversationType.name | ||||||
|  |  | ||||||
|  |     @detail_type.setter | ||||||
|  |     def detail_type(self, value) -> None: | ||||||
|  |         if value == "private": | ||||||
|  |             self.raw_event.conversationType = ConversationType.private | ||||||
|  |         if value == "group": | ||||||
|  |             self.raw_event.conversationType = ConversationType.group | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def sub_type(self) -> None: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``None`` | ||||||
|  |         - 说明: 钉钉适配器无事件子类型 | ||||||
|  |         """ | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |     @sub_type.setter | ||||||
|  |     def sub_type(self, value) -> None: | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def user_id(self) -> Optional[str]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[str]`` | ||||||
|  |         - 说明: 发送者 ID | ||||||
|  |         """ | ||||||
|  |         return self.raw_event.senderId | ||||||
|  |  | ||||||
|  |     @user_id.setter | ||||||
|  |     def user_id(self, value) -> None: | ||||||
|  |         self.raw_event.senderId = value | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def group_id(self) -> Optional[str]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[str]`` | ||||||
|  |         - 说明: 事件主体群 ID | ||||||
|  |         """ | ||||||
|  |         return self.raw_event.conversationId | ||||||
|  |  | ||||||
|  |     @group_id.setter | ||||||
|  |     def group_id(self, value) -> None: | ||||||
|  |         self.raw_event.conversationId = value | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def to_me(self) -> Optional[bool]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[bool]`` | ||||||
|  |         - 说明: 消息是否与机器人相关 | ||||||
|  |         """ | ||||||
|  |         return self.detail_type == "private" or self.raw_event.isInAtList | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def message(self) -> Optional["Message"]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[Message]`` | ||||||
|  |         - 说明: 消息内容 | ||||||
|  |         """ | ||||||
|  |         return self._message | ||||||
|  |  | ||||||
|  |     @message.setter | ||||||
|  |     def message(self, value) -> None: | ||||||
|  |         self._message = value | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def reply(self) -> None: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``None`` | ||||||
|  |         - 说明: 回复消息详情 | ||||||
|  |         """ | ||||||
|  |         raise ValueError("暂不支持 reply") | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def raw_message(self) -> Optional[Union[TextMessage]]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[str]`` | ||||||
|  |         - 说明: 原始消息 | ||||||
|  |         """ | ||||||
|  |         return getattr(self.raw_event, self.raw_event.msgtype) | ||||||
|  |  | ||||||
|  |     @raw_message.setter | ||||||
|  |     def raw_message(self, value) -> None: | ||||||
|  |         setattr(self.raw_event, self.raw_event.msgtype, value) | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def plain_text(self) -> Optional[str]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[str]`` | ||||||
|  |         - 说明: 纯文本消息内容 | ||||||
|  |         """ | ||||||
|  |         return self.message and self.message.extract_plain_text().strip() | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def sender(self) -> Optional[dict]: | ||||||
|  |         """ | ||||||
|  |         - 类型: ``Optional[dict]`` | ||||||
|  |         - 说明: 消息发送者信息 | ||||||
|  |         """ | ||||||
|  |         result = { | ||||||
|  |             # 加密的发送者ID。 | ||||||
|  |             "senderId": self.raw_event.senderId, | ||||||
|  |             # 发送者昵称。 | ||||||
|  |             "senderNick": self.raw_event.senderNick, | ||||||
|  |             # 企业内部群有的发送者当前群的企业 corpId。 | ||||||
|  |             "senderCorpId": self.raw_event.senderCorpId, | ||||||
|  |             # 企业内部群有的发送者在企业内的 userId。 | ||||||
|  |             "senderStaffId": self.raw_event.senderStaffId, | ||||||
|  |             "role": "admin" if self.raw_event.isAdmin else "member" | ||||||
|  |         } | ||||||
|  |         return result | ||||||
|  |  | ||||||
|  |     @sender.setter | ||||||
|  |     def sender(self, value) -> None: | ||||||
|  |  | ||||||
|  |         def set_wrapper(name): | ||||||
|  |             if value.get(name): | ||||||
|  |                 setattr(self.raw_event, name, value.get(name)) | ||||||
|  |  | ||||||
|  |         set_wrapper("senderId") | ||||||
|  |         set_wrapper("senderNick") | ||||||
|  |         set_wrapper("senderCorpId") | ||||||
|  |         set_wrapper("senderStaffId") | ||||||
							
								
								
									
										76
									
								
								nonebot/adapters/ding/exception.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								nonebot/adapters/ding/exception.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | from nonebot.typing import Optional | ||||||
|  | from nonebot.exception import (AdapterException, ActionFailed as | ||||||
|  |                                BaseActionFailed, ApiNotAvailable as | ||||||
|  |                                BaseApiNotAvailable, NetworkError as | ||||||
|  |                                BaseNetworkError) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class DingAdapterException(AdapterException): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       钉钉 Adapter 错误基类 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self) -> None: | ||||||
|  |         super().__init__("ding") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ActionFailed(BaseActionFailed, DingAdapterException): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       API 请求返回错误信息。 | ||||||
|  |  | ||||||
|  |     :参数: | ||||||
|  |  | ||||||
|  |       * ``errcode: Optional[int]``: 错误码 | ||||||
|  |       * ``errmsg: Optional[str]``: 错误信息 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, | ||||||
|  |                  errcode: Optional[int] = None, | ||||||
|  |                  errmsg: Optional[str] = None): | ||||||
|  |         super().__init__() | ||||||
|  |         self.errcode = errcode | ||||||
|  |         self.errmsg = errmsg | ||||||
|  |  | ||||||
|  |     def __repr__(self): | ||||||
|  |         return f"<ApiError errcode={self.errcode} errmsg={self.errmsg}>" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ApiNotAvailable(BaseApiNotAvailable, DingAdapterException): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class NetworkError(BaseNetworkError, DingAdapterException): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       网络错误。 | ||||||
|  |  | ||||||
|  |     :参数: | ||||||
|  |  | ||||||
|  |       * ``retcode: Optional[int]``: 错误码 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, msg: Optional[str] = None): | ||||||
|  |         super().__init__() | ||||||
|  |         self.msg = msg | ||||||
|  |  | ||||||
|  |     def __repr__(self): | ||||||
|  |         return f"<NetWorkError message={self.msg}>" | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.__repr__() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SessionExpired(BaseApiNotAvailable, DingAdapterException): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       发消息的 session 已经过期。 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __repr__(self) -> str: | ||||||
|  |         return f"<Session Webhook is Expired>" | ||||||
							
								
								
									
										133
									
								
								nonebot/adapters/ding/message.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								nonebot/adapters/ding/message.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | |||||||
|  | from nonebot.typing import Any, Dict, Union, Iterable | ||||||
|  | from nonebot.adapters import BaseMessage, BaseMessageSegment | ||||||
|  | from .utils import log | ||||||
|  | from .model import TextMessage | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MessageSegment(BaseMessageSegment): | ||||||
|  |     """ | ||||||
|  |     钉钉 协议 MessageSegment 适配。具体方法参考协议消息段类型或源码。 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, type_: str, msg: Dict[str, Any]) -> None: | ||||||
|  |         data = { | ||||||
|  |             "msgtype": type_, | ||||||
|  |         } | ||||||
|  |         if msg: | ||||||
|  |             data.update(msg) | ||||||
|  |         log("DEBUG", f"data {data}") | ||||||
|  |         super().__init__(type=type_, data=data) | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def from_segment(cls, segment: "MessageSegment"): | ||||||
|  |         return MessageSegment(segment.type, segment.data) | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         log("DEBUG", f"__str__: self.type {self.type} data {self.data}") | ||||||
|  |         if self.type == "text": | ||||||
|  |             return str(self.data["text"]["content"].strip()) | ||||||
|  |         return "" | ||||||
|  |  | ||||||
|  |     def __add__(self, other) -> "Message": | ||||||
|  |         if isinstance(other, str): | ||||||
|  |             if self.type == 'text': | ||||||
|  |                 self.data['text']['content'] += other | ||||||
|  |                 return MessageSegment.from_segment(self) | ||||||
|  |         return Message(self) + other | ||||||
|  |  | ||||||
|  |     def atMobile(self, mobileNumber): | ||||||
|  |         self.data.setdefault("at", {}) | ||||||
|  |         self.data["at"].setdefault("atMobiles", []) | ||||||
|  |         self.data["at"]["atMobiles"].append(mobileNumber) | ||||||
|  |  | ||||||
|  |     def atAll(self, value): | ||||||
|  |         self.data.setdefault("at", {}) | ||||||
|  |         self.data["at"]["isAtAll"] = value | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def text(text_: str) -> "MessageSegment": | ||||||
|  |         return MessageSegment("text", {"text": {"content": text_.strip()}}) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def markdown(title: str, text: str) -> "MessageSegment": | ||||||
|  |         return MessageSegment("markdown", { | ||||||
|  |             "markdown": { | ||||||
|  |                 "title": title, | ||||||
|  |                 "text": text, | ||||||
|  |             }, | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def actionCardSingleBtn(title: str, text: str, btnTitle: str, | ||||||
|  |                             btnUrl) -> "MessageSegment": | ||||||
|  |         return MessageSegment( | ||||||
|  |             "actionCard", { | ||||||
|  |                 "actionCard": { | ||||||
|  |                     "title": title, | ||||||
|  |                     "text": text, | ||||||
|  |                     "singleTitle": btnTitle, | ||||||
|  |                     "singleURL": btnUrl | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def actionCardSingleMultiBtns( | ||||||
|  |         title: str, | ||||||
|  |         text: str, | ||||||
|  |         btns: list = [], | ||||||
|  |         hideAvatar: bool = False, | ||||||
|  |         btnOrientation: str = '1', | ||||||
|  |     ) -> "MessageSegment": | ||||||
|  |         """ | ||||||
|  |         :参数: | ||||||
|  |  | ||||||
|  |             * ``btnOrientation``: 0:按钮竖直排列 1:按钮横向排列 | ||||||
|  |  | ||||||
|  |             * ``btns``: [{ "title": title, "actionURL": actionURL }, ...] | ||||||
|  |         """ | ||||||
|  |         return MessageSegment( | ||||||
|  |             "actionCard", { | ||||||
|  |                 "actionCard": { | ||||||
|  |                     "title": title, | ||||||
|  |                     "text": text, | ||||||
|  |                     "hideAvatar": "1" if hideAvatar else "0", | ||||||
|  |                     "btnOrientation": btnOrientation, | ||||||
|  |                     "btns": btns | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def feedCard(links: list = [],) -> "MessageSegment": | ||||||
|  |         """ | ||||||
|  |         :参数: | ||||||
|  |  | ||||||
|  |             * ``links``: [{ "title": xxx, "messageURL": xxx, "picURL": xxx }, ...] | ||||||
|  |         """ | ||||||
|  |         return MessageSegment("feedCard", {"feedCard": {"links": links}}) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def empty() -> "MessageSegment": | ||||||
|  |         """不想回复消息到群里""" | ||||||
|  |         return MessageSegment("empty") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Message(BaseMessage): | ||||||
|  |     """ | ||||||
|  |     钉钉 协议 Message 适配。 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def _construct( | ||||||
|  |             msg: Union[str, dict, list, | ||||||
|  |                        TextMessage]) -> Iterable[MessageSegment]: | ||||||
|  |         if isinstance(msg, dict): | ||||||
|  |             yield MessageSegment(msg["type"], msg.get("data") or {}) | ||||||
|  |             return | ||||||
|  |         elif isinstance(msg, list): | ||||||
|  |             for seg in msg: | ||||||
|  |                 yield MessageSegment(seg["type"], seg.get("data") or {}) | ||||||
|  |             return | ||||||
|  |         elif isinstance(msg, TextMessage): | ||||||
|  |             yield MessageSegment("text", {"text": msg.dict()}) | ||||||
|  |         elif isinstance(msg, str): | ||||||
|  |             yield MessageSegment.text(msg) | ||||||
							
								
								
									
										47
									
								
								nonebot/adapters/ding/model.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								nonebot/adapters/ding/model.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | from typing import List, Optional | ||||||
|  | from enum import Enum | ||||||
|  | from pydantic import BaseModel | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Headers(BaseModel): | ||||||
|  |     sign: str | ||||||
|  |     token: str | ||||||
|  |     # ms | ||||||
|  |     timestamp: int | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TextMessage(BaseModel): | ||||||
|  |     content: str | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class AtUsersItem(BaseModel): | ||||||
|  |     dingtalkId: str | ||||||
|  |     staffId: Optional[str] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ConversationType(str, Enum): | ||||||
|  |     private = '1' | ||||||
|  |     group = '2' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MessageModel(BaseModel): | ||||||
|  |     msgtype: str = None | ||||||
|  |     text: Optional[TextMessage] = None | ||||||
|  |     msgId: str | ||||||
|  |     # ms | ||||||
|  |     createAt: int = None | ||||||
|  |     conversationType: ConversationType = None | ||||||
|  |     conversationId: str = None | ||||||
|  |     conversationTitle: str = None | ||||||
|  |     senderId: str = None | ||||||
|  |     senderNick: str = None | ||||||
|  |     senderCorpId: str = None | ||||||
|  |     senderStaffId: str = None | ||||||
|  |     chatbotUserId: str = None | ||||||
|  |     chatbotCorpId: str = None | ||||||
|  |     atUsers: List[AtUsersItem] = None | ||||||
|  |     sessionWebhook: str = None | ||||||
|  |     # ms | ||||||
|  |     sessionWebhookExpiredTime: int = None | ||||||
|  |     isAdmin: bool = None | ||||||
|  |     isInAtList: bool = None | ||||||
							
								
								
									
										3
									
								
								nonebot/adapters/ding/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								nonebot/adapters/ding/utils.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | from nonebot.utils import logger_wrapper | ||||||
|  |  | ||||||
|  | log = logger_wrapper("DING") | ||||||
| @@ -6,10 +6,17 @@ | |||||||
| 这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 | 这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 | ||||||
| """ | """ | ||||||
|  |  | ||||||
| from nonebot.typing import List, Type, Optional |  | ||||||
|  | class NoneBotException(Exception): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       所有 NoneBot 发生的异常基类。 | ||||||
|  |     """ | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| class IgnoredException(Exception): | class IgnoredException(NoneBotException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -30,7 +37,7 @@ class IgnoredException(Exception): | |||||||
|         return self.__repr__() |         return self.__repr__() | ||||||
|  |  | ||||||
|  |  | ||||||
| class PausedException(Exception): | class PausedException(NoneBotException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -44,7 +51,7 @@ class PausedException(Exception): | |||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| class RejectedException(Exception): | class RejectedException(NoneBotException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -58,7 +65,7 @@ class RejectedException(Exception): | |||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| class FinishedException(Exception): | class FinishedException(NoneBotException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -72,7 +79,7 @@ class FinishedException(Exception): | |||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| class StopPropagation(Exception): | class StopPropagation(NoneBotException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -85,7 +92,7 @@ class StopPropagation(Exception): | |||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| class RequestDenied(Exception): | class RequestDenied(NoneBotException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -108,7 +115,22 @@ class RequestDenied(Exception): | |||||||
|         return self.__repr__() |         return self.__repr__() | ||||||
|  |  | ||||||
|  |  | ||||||
| class ApiNotAvailable(Exception): | class AdapterException(NoneBotException): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|  |       代表 ``Adapter`` 抛出的异常,所有的 ``Adapter`` 都要在内部继承自这个 ``Exception`` | ||||||
|  |  | ||||||
|  |     :参数: | ||||||
|  |  | ||||||
|  |       * ``adapter_name: str``: 标识 adapter | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def __init__(self, adapter_name: str) -> None: | ||||||
|  |         self.adapter_name = adapter_name | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ApiNotAvailable(AdapterException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -117,7 +139,7 @@ class ApiNotAvailable(Exception): | |||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| class NetworkError(Exception): | class NetworkError(AdapterException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
| @@ -126,22 +148,10 @@ class NetworkError(Exception): | |||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| class ActionFailed(Exception): | class ActionFailed(AdapterException): | ||||||
|     """ |     """ | ||||||
|     :说明: |     :说明: | ||||||
|  |  | ||||||
|       API 请求成功返回数据,但 API 操作失败。 |       API 请求成功返回数据,但 API 操作失败。 | ||||||
|  |  | ||||||
|     :参数: |  | ||||||
|  |  | ||||||
|       * ``retcode: Optional[int]``: 错误代码 |  | ||||||
|     """ |     """ | ||||||
|  |     pass | ||||||
|     def __init__(self, retcode: Optional[int]): |  | ||||||
|         self.retcode = retcode |  | ||||||
|  |  | ||||||
|     def __repr__(self): |  | ||||||
|         return f"<ActionFailed, retcode={self.retcode}>" |  | ||||||
|  |  | ||||||
|     def __str__(self): |  | ||||||
|         return self.__repr__() |  | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ | |||||||
| from types import ModuleType | from types import ModuleType | ||||||
| from typing import NoReturn, TYPE_CHECKING | from typing import NoReturn, TYPE_CHECKING | ||||||
| from typing import Any, Set, List, Dict, Type, Tuple, Mapping | from typing import Any, Set, List, Dict, Type, Tuple, Mapping | ||||||
| from typing import Union, TypeVar, Optional, Iterable, Callable, Awaitable | from typing import Union, TypeVar, Optional, Iterable, Callable, Awaitable, Generic | ||||||
|  |  | ||||||
| # import some modules needed when checking types | # import some modules needed when checking types | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import dataclasses | |||||||
| from functools import wraps, partial | from functools import wraps, partial | ||||||
|  |  | ||||||
| from nonebot.log import logger | from nonebot.log import logger | ||||||
| from nonebot.typing import Any, Callable, Awaitable, overrides | from nonebot.typing import Any, Optional, Callable, Awaitable, overrides | ||||||
|  |  | ||||||
|  |  | ||||||
| def escape_tag(s: str) -> str: | def escape_tag(s: str) -> str: | ||||||
| @@ -65,19 +65,20 @@ class DataclassEncoder(json.JSONEncoder): | |||||||
|  |  | ||||||
|  |  | ||||||
| def logger_wrapper(logger_name: str): | def logger_wrapper(logger_name: str): | ||||||
|  |     """ | ||||||
|  |     :说明: | ||||||
|  |  | ||||||
|     def log(level: str, message: str): |     用于打印 adapter 的日志。 | ||||||
|         """ |  | ||||||
|         :说明: |  | ||||||
|  |  | ||||||
|         用于打印 adapter 的日志。 |     :log 参数: | ||||||
|  |  | ||||||
|         :参数: |     * ``level: Literal['WARNING', 'DEBUG', 'INFO']``: 日志等级 | ||||||
|  |     * ``message: str``: 日志信息 | ||||||
|  |     * ``exception: Optional[Exception]``: 异常信息 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|         * ``level: Literal['WARNING', 'DEBUG', 'INFO']``: 日志等级 |     def log(level: str, message: str, exception: Optional[Exception] = None): | ||||||
|         * ``message: str``: 日志信息 |         return logger.opt(colors=True, exception=exception).log( | ||||||
|         """ |             level, f"<m>{logger_name}</m> | " + message) | ||||||
|         return logger.opt(colors=True).log(level, |  | ||||||
|                                            f"<m>{logger_name}</m> | " + message) |  | ||||||
|  |  | ||||||
|     return log |     return log | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ sys.path.insert(0, os.path.abspath("..")) | |||||||
|  |  | ||||||
| import nonebot | import nonebot | ||||||
| from nonebot.adapters.cqhttp import Bot | from nonebot.adapters.cqhttp import Bot | ||||||
|  | from nonebot.adapters.ding import Bot as DingBot | ||||||
| from nonebot.log import logger, default_format | from nonebot.log import logger, default_format | ||||||
|  |  | ||||||
| # test custom log | # test custom log | ||||||
| @@ -18,6 +19,7 @@ nonebot.init(custom_config2="config on init") | |||||||
| app = nonebot.get_asgi() | app = nonebot.get_asgi() | ||||||
| driver = nonebot.get_driver() | driver = nonebot.get_driver() | ||||||
| driver.register_adapter("cqhttp", Bot) | driver.register_adapter("cqhttp", Bot) | ||||||
|  | driver.register_adapter("ding", DingBot) | ||||||
|  |  | ||||||
| # load builtin plugin | # load builtin plugin | ||||||
| nonebot.load_builtin_plugins() | nonebot.load_builtin_plugins() | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ from nonebot.rule import to_me | |||||||
| from nonebot.typing import Event | from nonebot.typing import Event | ||||||
| from nonebot.plugin import on_startswith | from nonebot.plugin import on_startswith | ||||||
| from nonebot.adapters.cqhttp import Bot | from nonebot.adapters.cqhttp import Bot | ||||||
|  | from nonebot.adapters.ding import Bot as DingBot, Event as DingEvent | ||||||
| from nonebot.permission import GROUP_ADMIN | from nonebot.permission import GROUP_ADMIN | ||||||
|  |  | ||||||
| test_command = on_startswith("hello", to_me(), permission=GROUP_ADMIN) | test_command = on_startswith("hello", to_me(), permission=GROUP_ADMIN) | ||||||
| @@ -9,4 +10,9 @@ test_command = on_startswith("hello", to_me(), permission=GROUP_ADMIN) | |||||||
|  |  | ||||||
| @test_command.handle() | @test_command.handle() | ||||||
| async def test_handler(bot: Bot, event: Event, state: dict): | async def test_handler(bot: Bot, event: Event, state: dict): | ||||||
|     await test_command.finish("hello") |     await test_command.finish("cqhttp hello") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @test_command.handle() | ||||||
|  | async def test_handler(bot: DingBot, event: DingEvent, state: dict): | ||||||
|  |     await test_command.finish("ding hello") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user