From 5442e23384ba8a233d335d96a4cd06fee9bdf614 Mon Sep 17 00:00:00 2001 From: penguinboi Date: Sun, 12 Apr 2026 02:50:09 -0400 Subject: [PATCH] Fix error handling no throwing _on_command_error --- matrix/bot.py | 18 +++++++++++------- tests/test_bot.py | 40 ++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/matrix/bot.py b/matrix/bot.py index 3dad2df..a698e35 100644 --- a/matrix/bot.py +++ b/matrix/bot.py @@ -326,15 +326,19 @@ async def _dispatch_matrix_event(self, room: Room, event: Event) -> None: async def _process_commands(self, room: Room, event: Event) -> None: """Parse and execute commands""" - ctx = await self._build_context(room, event) + try: + ctx = await self._build_context(room, event) - if ctx.command: - for check in self._checks: - if not await check(ctx): - raise CheckError(ctx.command, check) + if ctx.command: + for check in self._checks: + if not await check(ctx): + raise CheckError(ctx.command, check) - await self._on_command(ctx) - await ctx.command(ctx) + await self._on_command(ctx) + await ctx.command(ctx) + except Exception as error: + ctx = Context(bot=self, room=room, event=event) + await self._on_command_error(ctx, error) async def _build_context(self, matrix_room: Room, event: Event) -> Context: room = self.get_room(matrix_room.room_id) diff --git a/tests/test_bot.py b/tests/test_bot.py index d98a27c..ec00baf 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -3,9 +3,7 @@ from unittest.mock import AsyncMock, MagicMock, patch from nio import MatrixRoom, RoomMessageText -from matrix.bot import Bot -from matrix.config import Config -from matrix.extension import Extension +from matrix.bot import Bot, Config, Extension, Room from matrix.errors import ( CheckError, CommandNotFoundError, @@ -118,7 +116,8 @@ async def handler2(room, event): "type": "m.room.message", } ) - room = MatrixRoom("!roomid:matrix.org", "room_alias") + matrix_room = MatrixRoom("!roomid:matrix.org", "room_alias") + room = Room(matrix_room, bot.client) await bot._dispatch_matrix_event(room, event) assert "h1" in called @@ -245,7 +244,9 @@ async def greet(ctx): @pytest.mark.asyncio -async def test_command_not_found_raises(bot): +async def test_command_not_found_calls_command_error_handler(bot): + bot._on_command_error = AsyncMock() + event = RoomMessageText.from_dict( { "content": {"body": "!nonexistent", "msgtype": "m.text"}, @@ -258,17 +259,14 @@ async def test_command_not_found_raises(bot): room = MatrixRoom("!roomid", "alias") - with patch("matrix.context.Context", autospec=True) as MockContext: - mock_ctx = MagicMock() - mock_ctx.body = "!nonexistent" - MockContext.return_value = mock_ctx + await bot._process_commands(room, event) - with pytest.raises(CommandNotFoundError): - await bot._process_commands(room, event) + bot._on_command_error.assert_awaited_once() + assert isinstance(bot._on_command_error.call_args[0][1], CommandNotFoundError) @pytest.mark.asyncio -async def test_bot_does_not_execute_when_global_check_fails(bot, event): +async def test_bot_does_not_execute_command_when_global_check_fails(bot): called = False @bot.command() @@ -280,6 +278,8 @@ async def greet(ctx): async def global_check(ctx): return False + bot._on_command_error = AsyncMock() + event = RoomMessageText.from_dict( { "content": {"body": "!greet", "msgtype": "m.text"}, @@ -290,18 +290,14 @@ async def global_check(ctx): } ) - room = MatrixRoom("!roomid", "alias") + matrix_room = MatrixRoom("!roomid", "alias") + room = Room(matrix_room, bot.client) - with patch("matrix.context.Context", autospec=True) as MockContext: - mock_ctx = MagicMock() - mock_ctx.body = "!greet" - mock_ctx.command = bot.commands["greet"] - MockContext.return_value = mock_ctx - - with pytest.raises(CheckError): - await bot._process_commands(room, event) + await bot._process_commands(room, event) - assert not called, "Expected command handler not to be called" + assert not called + bot._on_command_error.assert_awaited_once() + assert isinstance(bot._on_command_error.call_args[0][1], CheckError) @pytest.mark.asyncio