diff --git a/docs/api/exception.md b/docs/api/exception.md index bf281b11..984aa80c 100644 --- a/docs/api/exception.md +++ b/docs/api/exception.md @@ -43,11 +43,22 @@ sidebarDepth: 0 -## _exception_ `IgnoredException` +## _exception_ `ProcessException` 基类:`nonebot.exception.NoneBotException` +* **说明** + + 事件处理过程中发生的异常基类。 + + + +## _exception_ `IgnoredException` + +基类:`nonebot.exception.ProcessException` + + * **说明** 指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。 @@ -61,9 +72,27 @@ sidebarDepth: 0 +## _exception_ `MockApiException` + +基类:`nonebot.exception.ProcessException` + + +* **说明** + + 指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。可由 api hook 抛出。 + + + +* **参数** + + + * `result`: 返回的内容 + + + ## _exception_ `StopPropagation` -基类:`nonebot.exception.NoneBotException` +基类:`nonebot.exception.ProcessException` * **说明** diff --git a/nonebot/adapters/_bot.py b/nonebot/adapters/_bot.py index 6ed7b2b2..5e3aec7f 100644 --- a/nonebot/adapters/_bot.py +++ b/nonebot/adapters/_bot.py @@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any, Set, Tuple, Union, Optional from nonebot.log import logger from nonebot.config import Config +from nonebot.exception import MockApiException from nonebot.typing import T_CalledAPIHook, T_CallingAPIHook from nonebot.drivers import Driver, HTTPResponse, HTTPConnection @@ -137,24 +138,33 @@ class Bot(abc.ABC): await bot.call_api("send_msg", message="hello world") await bot.send_msg(message="hello world") """ + + result: Any = None + skip_calling_api: bool = False + exception: Optional[Exception] = None + coros = list(map(lambda x: x(self, api, data), self._calling_api_hook)) if coros: try: logger.debug("Running CallingAPI hooks...") await asyncio.gather(*coros) + except MockApiException as e: + skip_calling_api = True + result = e.result + logger.debug( + f"Calling API {api} is cancelled. Return {result} instead." + ) except Exception as e: logger.opt(colors=True, exception=e).error( "Error when running CallingAPI hook. " "Running cancelled!" ) - exception = None - result = None - - try: - result = await self._call_api(api, **data) - except Exception as e: - exception = e + if not skip_calling_api: + try: + result = await self._call_api(api, **data) + except Exception as e: + exception = e coros = list( map(lambda x: x(self, exception, api, data, result), self._called_api_hook) @@ -163,6 +173,11 @@ class Bot(abc.ABC): try: logger.debug("Running CalledAPI hooks...") await asyncio.gather(*coros) + except MockApiException as e: + result = e.result + logger.debug( + f"Calling API {api} result is mocked. Return {result} instead." + ) except Exception as e: logger.opt(colors=True, exception=e).error( "Error when running CalledAPI hook. " diff --git a/nonebot/exception.py b/nonebot/exception.py index e602ee93..193023b7 100644 --- a/nonebot/exception.py +++ b/nonebot/exception.py @@ -6,7 +6,7 @@ 这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 """ -from typing import Optional +from typing import Any, Optional class NoneBotException(Exception): @@ -42,7 +42,15 @@ class ParserExit(NoneBotException): # Processor Exception -class IgnoredException(NoneBotException): +class ProcessException(NoneBotException): + """ + :说明: + + 事件处理过程中发生的异常基类。 + """ + + +class IgnoredException(ProcessException): """ :说明: @@ -63,7 +71,28 @@ class IgnoredException(NoneBotException): return self.__repr__() -class StopPropagation(NoneBotException): +class MockApiException(ProcessException): + """ + :说明: + + 指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。可由 api hook 抛出。 + + :参数: + + * ``result``: 返回的内容 + """ + + def __init__(self, result: Any): + self.result = result + + def __repr__(self): + return f"" + + def __str__(self): + return self.__repr__() + + +class StopPropagation(ProcessException): """ :说明: