Skip to content

Commit

Permalink
✅ pass tests
Browse files Browse the repository at this point in the history
  • Loading branch information
yanyongyu authored Oct 22, 2024
1 parent 7ba290e commit 56ac77e
Show file tree
Hide file tree
Showing 36 changed files with 4,763 additions and 3,763 deletions.
2,029 changes: 1,110 additions & 919 deletions envs/pydantic-v1/poetry.lock

Large diffs are not rendered by default.

2,132 changes: 1,162 additions & 970 deletions envs/pydantic-v2/poetry.lock

Large diffs are not rendered by default.

1,394 changes: 832 additions & 562 deletions envs/test/poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions envs/test/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ packages = [{ include = "nonebot-test.py" }]

[tool.poetry.dependencies]
python = "^3.9"
nonebug = "^0.3.7"
trio = "^0.27.0"
nonebug = "^0.4.1"
wsproto = "^1.2.0"
pytest-cov = "^5.0.0"
pytest-xdist = "^3.0.2"
pytest-asyncio = "^0.23.2"
werkzeug = ">=2.3.6,<4.0.0"
coverage-conditional-plugin = "^0.9.0"

Expand Down
19 changes: 14 additions & 5 deletions nonebot/dependencies/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
from typing import Any, Generic, TypeVar, Callable, Optional, cast

import anyio
from exceptiongroup import BaseExceptionGroup, catch

from nonebot.log import logger
from nonebot.typing import _DependentCallable
from nonebot.exception import SkippedException
from nonebot.utils import run_sync, is_coroutine_callable
from nonebot.compat import FieldInfo, ModelField, PydanticUndefined
from nonebot.utils import run_sync, is_coroutine_callable, flatten_exception_group

from .utils import check_field_type, get_typed_signature

Expand Down Expand Up @@ -84,7 +85,16 @@ def __repr__(self) -> str:
)

async def __call__(self, **kwargs: Any) -> R:
try:
exception: Optional[BaseExceptionGroup[SkippedException]] = None

def _handle_skipped(exc_group: BaseExceptionGroup[SkippedException]):
nonlocal exception
exception = exc_group
# raise one of the exceptions instead
excs = list(flatten_exception_group(exc_group))
logger.trace(f"{self} skipped due to {excs}")

with catch({SkippedException: _handle_skipped}):
# do pre-check
await self.check(**kwargs)

Expand All @@ -96,9 +106,8 @@ async def __call__(self, **kwargs: Any) -> R:
return await cast(Callable[..., Awaitable[R]], self.call)(**values)
else:
return await run_sync(cast(Callable[..., R], self.call))(**values)
except SkippedException as e:
logger.trace(f"{self} skipped due to {e}")
raise

raise exception

@staticmethod
def parse_params(
Expand Down
9 changes: 5 additions & 4 deletions nonebot/drivers/none.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from nonebot.consts import WINDOWS
from nonebot.config import Env, Config
from nonebot.drivers import Driver as BaseDriver
from nonebot.utils import flatten_exception_group

HANDLED_SIGNALS = (
signal.SIGINT, # Unix signal 2. Sent by Ctrl+C.
Expand Down Expand Up @@ -92,10 +93,10 @@ def _handle_legacy_signal(self, sig, frame):
self.exit(force=self.should_exit.is_set())

async def _startup(self):

Check warning on line 95 in nonebot/drivers/none.py

View check run for this annotation

Codecov / codecov/patch

nonebot/drivers/none.py#L95

Added line #L95 was not covered by tests
def handle_exception(exc_group: BaseExceptionGroup) -> None:
def handle_exception(exc_group: BaseExceptionGroup[Exception]) -> None:
self.should_exit.set()

for exc in exc_group.exceptions:
for exc in flatten_exception_group(exc_group):

Check warning on line 99 in nonebot/drivers/none.py

View check run for this annotation

Codecov / codecov/patch

nonebot/drivers/none.py#L98-L99

Added lines #L98 - L99 were not covered by tests
logger.opt(colors=True, exception=exc).error(
"<r><bg #f8bbd0>Error occurred while running startup hook."
"</bg #f8bbd0></r>"

Check warning on line 102 in nonebot/drivers/none.py

View check run for this annotation

Codecov / codecov/patch

nonebot/drivers/none.py#L101-L102

Added lines #L101 - L102 were not covered by tests
Expand Down Expand Up @@ -128,12 +129,12 @@ async def _shutdown(self):

error_occurred: bool = False

Check warning on line 130 in nonebot/drivers/none.py

View check run for this annotation

Codecov / codecov/patch

nonebot/drivers/none.py#L130

Added line #L130 was not covered by tests

def handle_exception(exc_group: BaseExceptionGroup) -> None:
def handle_exception(exc_group: BaseExceptionGroup[Exception]) -> None:

Check warning on line 132 in nonebot/drivers/none.py

View check run for this annotation

Codecov / codecov/patch

nonebot/drivers/none.py#L132

Added line #L132 was not covered by tests
nonlocal error_occurred

error_occurred = True

for exc in exc_group.exceptions:
for exc in flatten_exception_group(exc_group):

Check warning on line 137 in nonebot/drivers/none.py

View check run for this annotation

Codecov / codecov/patch

nonebot/drivers/none.py#L137

Added line #L137 was not covered by tests
logger.opt(colors=True, exception=exc).error(
"<r><bg #f8bbd0>Error occurred while running shutdown hook."
"</bg #f8bbd0></r>"

Check warning on line 140 in nonebot/drivers/none.py

View check run for this annotation

Codecov / codecov/patch

nonebot/drivers/none.py#L139-L140

Added lines #L139 - L140 were not covered by tests
Expand Down
24 changes: 15 additions & 9 deletions nonebot/internal/adapter/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from nonebot.log import logger
from nonebot.config import Config
from nonebot.exception import MockApiException
from nonebot.utils import flatten_exception_group
from nonebot.typing import T_CalledAPIHook, T_CallingAPIHook

if TYPE_CHECKING:
Expand Down Expand Up @@ -81,12 +82,14 @@ async def call_api(self, api: str, **data: Any) -> Any:
if self._calling_api_hook:
logger.debug("Running CallingAPI hooks...")

def _handle_mock_api_exception(exc_group: BaseExceptionGroup) -> None:
def _handle_mock_api_exception(
exc_group: BaseExceptionGroup[MockApiException],
) -> None:
nonlocal skip_calling_api, result

excs = [
exc
for exc in exc_group.exceptions
for exc in flatten_exception_group(exc_group)
if isinstance(exc, MockApiException)
]
if len(excs) > 1:
Expand All @@ -101,8 +104,8 @@ def _handle_mock_api_exception(exc_group: BaseExceptionGroup) -> None:
f"Calling API {api} is cancelled. Return {result!r} instead."
)

def _handle_exception(exc_group: BaseExceptionGroup) -> None:
for exc in exc_group.exceptions:
def _handle_exception(exc_group: BaseExceptionGroup[Exception]) -> None:
for exc in flatten_exception_group(exc_group):
logger.opt(colors=True, exception=exc).error(

Check warning on line 109 in nonebot/internal/adapter/bot.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/adapter/bot.py#L108-L109

Added lines #L108 - L109 were not covered by tests
"<r><bg #f8bbd0>Error when running CallingAPI hook. "
"Running cancelled!</bg #f8bbd0></r>"
Expand All @@ -127,12 +130,14 @@ def _handle_exception(exc_group: BaseExceptionGroup) -> None:
if self._called_api_hook:
logger.debug("Running CalledAPI hooks...")

def _handle_mock_api_exception(exc_group: BaseExceptionGroup) -> None:
nonlocal result
def _handle_mock_api_exception(
exc_group: BaseExceptionGroup[MockApiException],
) -> None:
nonlocal result, exception

excs = [
exc
for exc in exc_group.exceptions
for exc in flatten_exception_group(exc_group)
if isinstance(exc, MockApiException)
]
if len(excs) > 1:
Expand All @@ -141,12 +146,13 @@ def _handle_mock_api_exception(exc_group: BaseExceptionGroup) -> None:
)
elif excs:
result = excs[0].result
exception = None
logger.debug(
f"Calling API {api} result is mocked. Return {result} instead."
)

def _handle_exception(exc_group: BaseExceptionGroup) -> None:
for exc in exc_group.exceptions:
def _handle_exception(exc_group: BaseExceptionGroup[Exception]) -> None:
for exc in flatten_exception_group(exc_group):
logger.opt(colors=True, exception=exc).error(

Check warning on line 156 in nonebot/internal/adapter/bot.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/adapter/bot.py#L155-L156

Added lines #L155 - L156 were not covered by tests
"<r><bg #f8bbd0>Error when running CalledAPI hook. "
"Running cancelled!</bg #f8bbd0></r>"
Expand Down
2 changes: 2 additions & 0 deletions nonebot/internal/driver/_lifespan.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ async def shutdown(
with suppress(Exception):
await self.task_group.__aexit__(exc_type, exc_val, exc_tb)

self._task_group = None

if self._shutdown_funcs:
# reverse shutdown funcs to ensure stack order
await self._run_lifespan_func(reversed(self._shutdown_funcs))
Expand Down
6 changes: 3 additions & 3 deletions nonebot/internal/driver/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from nonebot.config import Env, Config
from nonebot.dependencies import Dependent
from nonebot.exception import SkippedException
from nonebot.utils import escape_tag, run_coro_with_catch
from nonebot.internal.params import BotParam, DependParam, DefaultParam
from nonebot.utils import escape_tag, run_coro_with_catch, flatten_exception_group
from nonebot.typing import (
T_DependencyCache,
T_BotConnectionHook,
Expand Down Expand Up @@ -159,7 +159,7 @@ def _bot_connect(self, bot: "Bot") -> None:
self._bots[bot.self_id] = bot

def handle_exception(exc_group: BaseExceptionGroup) -> None:
for exc in exc_group.exceptions:
for exc in flatten_exception_group(exc_group):
logger.opt(colors=True, exception=exc).error(

Check warning on line 163 in nonebot/internal/driver/abstract.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/driver/abstract.py#L162-L163

Added lines #L162 - L163 were not covered by tests
"<r><bg #f8bbd0>"
"Error when running WebSocketConnection hook:"
Expand Down Expand Up @@ -187,7 +187,7 @@ def _bot_disconnect(self, bot: "Bot") -> None:
del self._bots[bot.self_id]

def handle_exception(exc_group: BaseExceptionGroup) -> None:
for exc in exc_group.exceptions:
for exc in flatten_exception_group(exc_group):
logger.opt(colors=True, exception=exc).error(

Check warning on line 191 in nonebot/internal/driver/abstract.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/driver/abstract.py#L190-L191

Added lines #L190 - L191 were not covered by tests
"<r><bg #f8bbd0>"
"Error when running WebSocketDisConnection hook:"
Expand Down
102 changes: 76 additions & 26 deletions nonebot/internal/matcher/matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
overload,
)

from exceptiongroup import BaseExceptionGroup, catch

from nonebot.log import logger
from nonebot.internal.rule import Rule
from nonebot.utils import classproperty
from nonebot.dependencies import Param, Dependent
from nonebot.internal.permission import User, Permission
from nonebot.utils import classproperty, flatten_exception_group
from nonebot.internal.adapter import (
Bot,
Event,
Expand Down Expand Up @@ -812,28 +814,34 @@ async def simple_run(
f"bot={bot}, event={event!r}, state={state!r}"
)

def _handle_stop_propagation(exc_group: BaseExceptionGroup[StopPropagation]):
self.block = True

Check warning on line 818 in nonebot/internal/matcher/matcher.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/matcher/matcher.py#L818

Added line #L818 was not covered by tests

with self.ensure_context(bot, event):
try:
# Refresh preprocess state
self.state.update(state)

while self.remain_handlers:
handler = self.remain_handlers.pop(0)
current_handler.set(handler)
logger.debug(f"Running handler {handler}")
try:
await handler(
matcher=self,
bot=bot,
event=event,
state=self.state,
stack=stack,
dependency_cache=dependency_cache,
)
except SkippedException:
logger.debug(f"Handler {handler} skipped")
except StopPropagation:
self.block = True
with catch({StopPropagation: _handle_stop_propagation}):
# Refresh preprocess state
self.state.update(state)

while self.remain_handlers:
handler = self.remain_handlers.pop(0)
current_handler.set(handler)
logger.debug(f"Running handler {handler}")

def _handle_skipped(
exc_group: BaseExceptionGroup[SkippedException],
):
logger.debug(f"Handler {handler} skipped")

with catch({SkippedException: _handle_skipped}):
await handler(
matcher=self,
bot=bot,
event=event,
state=self.state,
stack=stack,
dependency_cache=dependency_cache,
)
finally:
logger.info(f"{self} running complete")

Expand All @@ -846,10 +854,54 @@ async def run(
stack: Optional[AsyncExitStack] = None,
dependency_cache: Optional[T_DependencyCache] = None,
):
try:
exc: Optional[Union[FinishedException, RejectedException, PausedException]] = (
None
)

def _handle_special_exception(
exc_group: BaseExceptionGroup[
Union[FinishedException, RejectedException, PausedException]
]
):
nonlocal exc
excs = list(flatten_exception_group(exc_group))
if len(excs) > 1:
logger.warning(

Check warning on line 869 in nonebot/internal/matcher/matcher.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/matcher/matcher.py#L869

Added line #L869 was not covered by tests
"Multiple session control exceptions occurred. "
"NoneBot will choose the proper one."
)
finished_exc = next(

Check warning on line 873 in nonebot/internal/matcher/matcher.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/matcher/matcher.py#L873

Added line #L873 was not covered by tests
(e for e in excs if isinstance(e, FinishedException)),
None,
)
rejected_exc = next(

Check warning on line 877 in nonebot/internal/matcher/matcher.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/matcher/matcher.py#L877

Added line #L877 was not covered by tests
(e for e in excs if isinstance(e, RejectedException)),
None,
)
paused_exc = next(

Check warning on line 881 in nonebot/internal/matcher/matcher.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/matcher/matcher.py#L881

Added line #L881 was not covered by tests
(e for e in excs if isinstance(e, PausedException)),
None,
)
exc = finished_exc or rejected_exc or paused_exc

Check warning on line 885 in nonebot/internal/matcher/matcher.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/matcher/matcher.py#L885

Added line #L885 was not covered by tests
elif isinstance(
excs[0], (FinishedException, RejectedException, PausedException)
):
exc = excs[0]

with catch(
{
(
FinishedException,
RejectedException,
PausedException,
): _handle_special_exception
}
):
await self.simple_run(bot, event, state, stack, dependency_cache)

except RejectedException:
if isinstance(exc, FinishedException):
pass
elif isinstance(exc, RejectedException):
await self.resolve_reject()
type_ = await self.update_type(bot, event, stack, dependency_cache)
permission = await self.update_permission(
Expand All @@ -870,7 +922,7 @@ async def run(
default_type_updater=self.__class__._default_type_updater,
default_permission_updater=self.__class__._default_permission_updater,
)
except PausedException:
elif isinstance(exc, PausedException):
type_ = await self.update_type(bot, event, stack, dependency_cache)
permission = await self.update_permission(
bot, event, stack, dependency_cache
Expand All @@ -890,5 +942,3 @@ async def run(
default_type_updater=self.__class__._default_type_updater,
default_permission_updater=self.__class__._default_permission_updater,
)
except FinishedException:
pass
22 changes: 17 additions & 5 deletions nonebot/internal/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
)

import anyio
from exceptiongroup import BaseExceptionGroup, catch
from pydantic.fields import FieldInfo as PydanticFieldInfo

from nonebot.exception import SkippedException
from nonebot.dependencies import Param, Dependent
from nonebot.dependencies.utils import check_field_type
from nonebot.compat import FieldInfo, ModelField, PydanticUndefined, extract_field_info
Expand Down Expand Up @@ -264,11 +266,21 @@ async def _solve(
call = cast(Callable[..., Any], sub_dependent.call)

# solve sub dependency with current cache
sub_values = await sub_dependent.solve(
stack=stack,
dependency_cache=dependency_cache,
**kwargs,
)
exc: Optional[BaseExceptionGroup[SkippedException]] = None

def _handle_skipped(exc_group: BaseExceptionGroup[SkippedException]):
nonlocal exc
exc = exc_group

Check warning on line 273 in nonebot/internal/params.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/params.py#L273

Added line #L273 was not covered by tests

with catch({SkippedException: _handle_skipped}):
sub_values = await sub_dependent.solve(
stack=stack,
dependency_cache=dependency_cache,
**kwargs,
)

if exc is not None:
raise exc

Check warning on line 283 in nonebot/internal/params.py

View check run for this annotation

Codecov / codecov/patch

nonebot/internal/params.py#L283

Added line #L283 was not covered by tests

# run dependency function
if use_cache and call in dependency_cache:
Expand Down
4 changes: 3 additions & 1 deletion nonebot/internal/permission.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,15 @@ async def __call__(

async def _run_checker(checker: Dependent[bool]) -> None:
nonlocal result
result |= await run_coro_with_catch(
# calculate the result first to avoid data racing
is_passed = await run_coro_with_catch(
checker(
bot=bot, event=event, stack=stack, dependency_cache=dependency_cache
),
(SkippedException,),
False,
)
result |= is_passed

async with anyio.create_task_group() as tg:
for checker in self.checkers:
Expand Down
Loading

0 comments on commit 56ac77e

Please sign in to comment.