From 66f8722163f94d14fcd5ca7213b84185a8140a0a Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 19 Jun 2025 22:07:57 -0700 Subject: [PATCH 01/39] Add support for message reactions and improve content creation in Message class --- matrix/message.py | 55 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index e6f4b50..3d5ffe4 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -1,6 +1,7 @@ from matrix.errors import MatrixError import markdown from typing import Dict, Optional +from nio import Event class Message: @@ -47,7 +48,14 @@ async def _send_to_room( except Exception as e: raise MatrixError(f"Failed to send message: {e}") - def _make_content(self, body: str, html: Optional[bool]) -> Dict: + def _make_content( + self, + body: str, + html: Optional[bool] = None, + reaction: Optional[bool] = None, + event_id: Optional[str] = None, + key: Optional[str] = None, + ) -> Dict: """ Create the content dictionary for a message. @@ -55,6 +63,12 @@ def _make_content(self, body: str, html: Optional[bool]) -> Dict: :type body: str :param html: Wheter to format the message as HTML. :type html: bool + :param reaction: Wheter to format the context with a reaction event. + :type reaction: bool + :param event_id: The ID of the event to react to. + :type event_id: str + :param key: The reaction to the message. + :type key: Optional[str] :return: The content of the dictionary. """ @@ -68,10 +82,18 @@ def _make_content(self, body: str, html: Optional[bool]) -> Dict: base["format"] = self.MATRIX_CUSTOM_HTML base["formatted_body"] = html_body + if reaction: + base["m.relates_to"] = { + "event_id": event_id, + "key": key, + "rel_type": "m.annotation", + } + return base async def send( - self, room_id: str, + self, + room_id: str, message: str, format_markdown: Optional[bool] = True ) -> None: @@ -88,5 +110,32 @@ async def send( """ await self._send_to_room( room_id=room_id, - content=self._make_content(message, format_markdown), + content=self._make_content(body=message, html=format_markdown), + ) + + async def send_reaction( + self, room_id: str, event: Event, key: str + ) -> None: + """ + Send a reaction to a message from a user in a Matrix room. + + :param room_id: The ID of the room to send the message to. + :type room_id: str + :param event: The event object to react to. + :type event: Event + :param key: The reaction to the message. + :type key: str + """ + if isinstance(event, Event): + event_id = event.event_id + else: + event_id = event + print("hi") + + await self._send_to_room( + room_id=room_id, + content=self._make_content( + body="", event_id=event_id, key=key, reaction=True + ), + message_type="m.reaction", ) From 28d5ce7239c9fc76f49682ab5693a0a951e750b2 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 19 Jun 2025 22:08:09 -0700 Subject: [PATCH 02/39] Refactor send method in Room class to support message reactions and improve parameter handling --- matrix/room.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/matrix/room.py b/matrix/room.py index c88687a..dbff466 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -1,6 +1,7 @@ from matrix.errors import MatrixError from matrix.message import Message from typing import TYPE_CHECKING, Optional +from nio import Event if TYPE_CHECKING: from matrix.bot import Bot # pragma: no cover @@ -21,23 +22,32 @@ def __init__(self, room_id: str, bot: "Bot") -> None: self.bot = bot async def send( - self, - message: str, - markdown: Optional[bool] = True + self, + message: Optional[str] = None, + markdown: Optional[bool] = True, + event: Optional[Event] = None, + key: Optional[str] = None, ) -> None: """ Send a message to the room. :param message: The message to send. - :type message: str + :type message: Optional[str] :param markdown: Whether to format the message as Markdown. - :type markdown: bool + :type markdown: Optional[bool] + :param event: An event object to react to. + :type event: Optional[Event] + :param key: The reaction to the message. + :type key: Optional[str] :raises MatrixError: If sending the message fails. """ try: room = Message(self.bot) - await room.send(self.room_id, message, markdown) + if key: + await room.send_reaction(self.room_id, event, key) + else: + await room.send(self.room_id, message, markdown) except Exception as e: raise MatrixError(f"Failed to send message: {e}") From c40bca9c1e85d9f9a719979bd50a89b9bddc5ac5 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 19 Jun 2025 22:09:27 -0700 Subject: [PATCH 03/39] Fix ping command to use reply method instead of send --- examples/ping.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/ping.py b/examples/ping.py index e0692d5..d34c4c2 100644 --- a/examples/ping.py +++ b/examples/ping.py @@ -1,13 +1,12 @@ from matrix.bot import Bot, Context - -bot = Bot('examples/config.yaml') +bot = Bot("examples/config.yaml") @bot.command("ping") async def ping(ctx: Context): print(f"{ctx.sender} invoked {ctx.body} in room {ctx.room_name}.") - await ctx.send("Pong!") + await ctx.reply("Pong!") bot.start() From ca82eb50c048334086a6f8a3c925c57110721a9b Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 19 Jun 2025 22:10:25 -0700 Subject: [PATCH 04/39] Add reaction event example to respond to specific messages --- examples/reaction.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 examples/reaction.py diff --git a/examples/reaction.py b/examples/reaction.py new file mode 100644 index 0000000..bf8fe09 --- /dev/null +++ b/examples/reaction.py @@ -0,0 +1,18 @@ +from matrix.bot import Bot +from nio import RoomMessageText + +bot = Bot("examples/config.yaml") + + +@bot.event(event_spec=RoomMessageText) +async def react_event(room, event): + room = bot.get_room(room.room_id) + if event.body.lower().startswith("thanks"): + await room.send(event=event, key="🙏") + + if event.body.lower().startswith("hello"): + # Can also react with a text message instead of emoji + await room.send(event=event, key="hi") + + +bot.start() From 7cd47d2a6143714c800e9d4b49fea9d09d7826ab Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 19 Jun 2025 22:15:36 -0700 Subject: [PATCH 05/39] Remove debug print statement from send_reaction method --- matrix/message.py | 1 - 1 file changed, 1 deletion(-) diff --git a/matrix/message.py b/matrix/message.py index 3d5ffe4..5c0c8b6 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -130,7 +130,6 @@ async def send_reaction( event_id = event.event_id else: event_id = event - print("hi") await self._send_to_room( room_id=room_id, From e1f328b14d20c78d4fb62024f27d69f3c2f937cc Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 20 Jun 2025 11:08:29 -0700 Subject: [PATCH 06/39] Add unit tests for send_reaction method in Message class --- tests/test_message.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_message.py b/tests/test_message.py index 4ca025b..5d0b630 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -3,6 +3,7 @@ from matrix.message import Message from matrix.errors import MatrixError from unittest.mock import AsyncMock, MagicMock +from nio import RoomMessageText @pytest.fixture @@ -17,6 +18,19 @@ def message_default(): return Message(bot) +@pytest.fixture +def event(): + return RoomMessageText.from_dict( + { + "content": {"body": "hello", "msgtype": "m.text"}, + "event_id": "$id", + "origin_server_ts": 123456, + "sender": "@user:matrix.org", + "type": "m.room.message", + } + ) + + @pytest.mark.asyncio async def test_send_message_success(message_default): room_id = "!room:id" @@ -56,3 +70,22 @@ def test_make_content_without_html(message_default): assert content["body"] == body assert "format" not in content assert "formatted_body" not in content + + +@pytest.mark.asyncio +async def test_send_reaction_success(message_default, event): + room_id = "!room:id" + + await message_default.send_reaction(room_id, event, "hi") + message_default.bot.client.room_send.assert_awaited_once() + + +@pytest.mark.asyncio +async def test_send_reaction_failure(message_default, event): + room_id = "!room:id" + + message_default.bot.client.room_send.side_effect = Exception( + "Failed to send message" + ) + with pytest.raises(MatrixError, match="Failed to send message"): + await message_default.send_reaction(room_id, event, "🙏") From 312073778ef504637bd8125b8e0854d974ddfdc8 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 20 Jun 2025 11:17:45 -0700 Subject: [PATCH 07/39] Update Message class to allow optional message body in send method and improve reaction handling --- matrix/message.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index 5c0c8b6..53b49a3 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -50,7 +50,7 @@ async def _send_to_room( def _make_content( self, - body: str, + body: Optional[str] = "", html: Optional[bool] = None, reaction: Optional[bool] = None, event_id: Optional[str] = None, @@ -94,7 +94,7 @@ def _make_content( async def send( self, room_id: str, - message: str, + message: Optional[str], format_markdown: Optional[bool] = True ) -> None: """ @@ -134,7 +134,7 @@ async def send_reaction( await self._send_to_room( room_id=room_id, content=self._make_content( - body="", event_id=event_id, key=key, reaction=True + event_id=event_id, key=key, reaction=True ), message_type="m.reaction", ) From 7cdd0bd1ea14cb809328fd16931e5a13295e5b00 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 20 Jun 2025 11:22:05 -0700 Subject: [PATCH 08/39] Refactor Message and Room classes to enforce non-optional message body parameters in send methods --- matrix/message.py | 4 ++-- matrix/room.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index 53b49a3..22ef8d2 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -50,7 +50,7 @@ async def _send_to_room( def _make_content( self, - body: Optional[str] = "", + body: str = "", html: Optional[bool] = None, reaction: Optional[bool] = None, event_id: Optional[str] = None, @@ -94,7 +94,7 @@ def _make_content( async def send( self, room_id: str, - message: Optional[str], + message: str, format_markdown: Optional[bool] = True ) -> None: """ diff --git a/matrix/room.py b/matrix/room.py index dbff466..6567bd2 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -23,7 +23,7 @@ def __init__(self, room_id: str, bot: "Bot") -> None: async def send( self, - message: Optional[str] = None, + message: str = "", markdown: Optional[bool] = True, event: Optional[Event] = None, key: Optional[str] = None, From b57b463497ce914fbf4871c27e18c6714fbccb8a Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 21 Jun 2025 23:00:29 -0700 Subject: [PATCH 09/39] Add 'on_react' event to EVENT_MAP in Bot class --- matrix/bot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix/bot.py b/matrix/bot.py index 25e5873..698402e 100644 --- a/matrix/bot.py +++ b/matrix/bot.py @@ -50,6 +50,7 @@ class Bot: EVENT_MAP: Dict[str, Type[Event]] = { "on_typing": TypingNoticeEvent, "on_message": RoomMessageText, + "on_react": RoomMessageText, "on_member_join": RoomMemberEvent, "on_member_leave": RoomMemberEvent, "on_member_invite": RoomMemberEvent, From e2b8f09dc6bee12878deef10b87bfdccb4347222 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 21 Jun 2025 23:00:43 -0700 Subject: [PATCH 10/39] Update event specification for react_event to use 'on_react' --- examples/reaction.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/reaction.py b/examples/reaction.py index bf8fe09..345ee98 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -1,10 +1,9 @@ from matrix.bot import Bot -from nio import RoomMessageText bot = Bot("examples/config.yaml") -@bot.event(event_spec=RoomMessageText) +@bot.event(event_spec="on_react") async def react_event(room, event): room = bot.get_room(room.room_id) if event.body.lower().startswith("thanks"): From 384ea9f382f6550cffa345a1b086d9d6197f9d53 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 10:07:23 -0700 Subject: [PATCH 11/39] Mapped 'on_message_react' and 'on_member_react' events --- matrix/bot.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/matrix/bot.py b/matrix/bot.py index 698402e..8ce9a86 100644 --- a/matrix/bot.py +++ b/matrix/bot.py @@ -20,6 +20,7 @@ RoomMessageText, RoomMemberEvent, TypingNoticeEvent, + ReactionEvent, ) from matrix.room import Room from matrix.config import Config @@ -50,7 +51,8 @@ class Bot: EVENT_MAP: Dict[str, Type[Event]] = { "on_typing": TypingNoticeEvent, "on_message": RoomMessageText, - "on_react": RoomMessageText, + "on_message_react": RoomMessageText, + "on_member_react": ReactionEvent, "on_member_join": RoomMemberEvent, "on_member_leave": RoomMemberEvent, "on_member_invite": RoomMemberEvent, From cb1fe105535c6689427a149871c347c527ee4345 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 10:08:07 -0700 Subject: [PATCH 12/39] Refactor reaction event handlers to improve clarity --- examples/reaction.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/reaction.py b/examples/reaction.py index 345ee98..2bcabf0 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -3,8 +3,8 @@ bot = Bot("examples/config.yaml") -@bot.event(event_spec="on_react") -async def react_event(room, event): +@bot.event +async def on_message_react(room, event): room = bot.get_room(room.room_id) if event.body.lower().startswith("thanks"): await room.send(event=event, key="🙏") @@ -14,4 +14,15 @@ async def react_event(room, event): await room.send(event=event, key="hi") +@bot.event +async def on_member_react(room, event): + room = bot.get_room(room.room_id) + + emoji = event.key + event_id = event.source["content"]["m.relates_to"]["event_id"] + + if emoji == "🙏": + await room.send(event=event_id, key="❤️") + + bot.start() From 7575446879b5625d8f6a1b202279ed945c5e040d Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 10:17:22 -0700 Subject: [PATCH 13/39] Added detailed docstrings and additional emoji reactions --- examples/reaction.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/examples/reaction.py b/examples/reaction.py index 2bcabf0..ba35ec8 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -5,6 +5,10 @@ @bot.event async def on_message_react(room, event): + """ + This function listens for new messages in a room and reacts based + on the message content. + """ room = bot.get_room(room.room_id) if event.body.lower().startswith("thanks"): await room.send(event=event, key="🙏") @@ -13,9 +17,16 @@ async def on_message_react(room, event): # Can also react with a text message instead of emoji await room.send(event=event, key="hi") + if event.body.lower().startswith("❤️"): + await room.send(event=event, message="❤️") + @bot.event async def on_member_react(room, event): + """ + This function listens for new member reaction to messages in a room, + and reacts based on the reaction emoji. + """ room = bot.get_room(room.room_id) emoji = event.key @@ -24,5 +35,8 @@ async def on_member_react(room, event): if emoji == "🙏": await room.send(event=event_id, key="❤️") + if emoji == "❤️": + await room.send(message="❤️") + bot.start() From e8c5449fffd7eb8c30b6b9dfdce9594db2e54aaf Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 10:17:50 -0700 Subject: [PATCH 14/39] Update type hints in Message and Room classes docstrings. --- matrix/message.py | 8 ++++---- matrix/room.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index 22ef8d2..7784eb7 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -62,11 +62,11 @@ def _make_content( :param body: The body of the message. :type body: str :param html: Wheter to format the message as HTML. - :type html: bool + :type html: Optional[bool] :param reaction: Wheter to format the context with a reaction event. - :type reaction: bool + :type reaction: Optional[bool] :param event_id: The ID of the event to react to. - :type event_id: str + :type event_id: Optional[str] :param key: The reaction to the message. :type key: Optional[str] @@ -106,7 +106,7 @@ async def send( :type message: str :param format_markdown: Whether to format the message as Markdown (default to True). - :type format_markdown: bool + :type format_markdown: Optional[bool] """ await self._send_to_room( room_id=room_id, diff --git a/matrix/room.py b/matrix/room.py index 8003cbe..6e2d8ec 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -32,7 +32,7 @@ async def send( Send a message to the room. :param message: The message to send. - :type message: Optional[str] + :type message: str :param markdown: Whether to format the message as Markdown. :type markdown: Optional[bool] :param event: An event object to react to. @@ -79,7 +79,7 @@ async def ban_user( :param user_id: The ID of the user to ban of the room. :type user_id: str :param reason: The reason to ban the user. - :type reason: str + :type reason: Optional[str] :raises MatrixError: If banning the user fails. """ @@ -122,7 +122,7 @@ async def kick_user( :param user_id: The ID of the user to kick of the room. :type user_id: str :param reason: The reason to kick the user. - :type reason: str + :type reason: Optional[str] :raises MatrixError: If kicking the user fails. """ From 145527878098f2f168f4ee45ecfea66d269ba0ef Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 10:57:33 -0700 Subject: [PATCH 15/39] Rename event handlers for message and member reactions for consistency --- examples/reaction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/reaction.py b/examples/reaction.py index ba35ec8..80bac69 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -4,7 +4,7 @@ @bot.event -async def on_message_react(room, event): +async def on_message(room, event): """ This function listens for new messages in a room and reacts based on the message content. @@ -22,7 +22,7 @@ async def on_message_react(room, event): @bot.event -async def on_member_react(room, event): +async def on_react(room, event): """ This function listens for new member reaction to messages in a room, and reacts based on the reaction emoji. From a00ad7fe505925dd18b941aae141e9c2a107399d Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 10:57:40 -0700 Subject: [PATCH 16/39] Consolidate reaction event handlers to improve consistency --- matrix/bot.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/matrix/bot.py b/matrix/bot.py index 8ce9a86..5d693f9 100644 --- a/matrix/bot.py +++ b/matrix/bot.py @@ -51,8 +51,7 @@ class Bot: EVENT_MAP: Dict[str, Type[Event]] = { "on_typing": TypingNoticeEvent, "on_message": RoomMessageText, - "on_message_react": RoomMessageText, - "on_member_react": ReactionEvent, + "on_react": ReactionEvent, "on_member_join": RoomMemberEvent, "on_member_leave": RoomMemberEvent, "on_member_invite": RoomMemberEvent, From febbc448368081d46f6fec36fecc79baed4f1dab Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 15:07:43 -0700 Subject: [PATCH 17/39] Fix variable name mismatch of its purpose --- matrix/room.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix/room.py b/matrix/room.py index 6e2d8ec..540659d 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -43,11 +43,11 @@ async def send( :raises MatrixError: If sending the message fails. """ try: - room = Message(self.bot) + message = Message(self.bot) if key: - await room.send_reaction(self.room_id, event, key) + await message.send_reaction(self.room_id, event, key) else: - await room.send(self.room_id, message, markdown) + await message.send(self.room_id, message, markdown) except Exception as e: raise MatrixError(f"Failed to send message: {e}") From c610201cac044a32f17dddfcdceda1d2bf22ee65 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 22 Jun 2025 15:19:30 -0700 Subject: [PATCH 18/39] Refactor message variable to msg to avoid variable naming clash --- matrix/room.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix/room.py b/matrix/room.py index 540659d..0e1f64a 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -43,11 +43,11 @@ async def send( :raises MatrixError: If sending the message fails. """ try: - message = Message(self.bot) + msg = Message(self.bot) if key: - await message.send_reaction(self.room_id, event, key) + await msg.send_reaction(self.room_id, event, key) else: - await message.send(self.room_id, message, markdown) + await msg.send(self.room_id, message, markdown) except Exception as e: raise MatrixError(f"Failed to send message: {e}") From 9e164a21f89f49da081ab36c222721d222fd3385 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:03:52 -0700 Subject: [PATCH 19/39] refactor reaction example --- examples/reaction.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/examples/reaction.py b/examples/reaction.py index 80bac69..b9d6250 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -18,7 +18,8 @@ async def on_message(room, event): await room.send(event=event, key="hi") if event.body.lower().startswith("❤️"): - await room.send(event=event, message="❤️") + # Or directly reply as a message instead of a reaction + await room.send(message="❤️") @bot.event @@ -29,14 +30,8 @@ async def on_react(room, event): """ room = bot.get_room(room.room_id) - emoji = event.key - event_id = event.source["content"]["m.relates_to"]["event_id"] - - if emoji == "🙏": - await room.send(event=event_id, key="❤️") - - if emoji == "❤️": - await room.send(message="❤️") + if event.key == "🙏": + await room.react(event, "hi") bot.start() From 73ba151c7aa03d9a07b7f0e35421f0f87ed8974e Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:05:12 -0700 Subject: [PATCH 20/39] rerfactor how to get construct message reaction and send --- matrix/context.py | 2 +- matrix/message.py | 69 +++++++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/matrix/context.py b/matrix/context.py index f936cdf..a173e2e 100644 --- a/matrix/context.py +++ b/matrix/context.py @@ -73,6 +73,6 @@ async def reply(self, message: str) -> None: try: c = Message(self.bot) - await c.send(room_id=self.room_id, message=message) + await c.send_message(room_id=self.room_id, message=message) except Exception as e: raise MatrixError(f"Failed to send message: {e}") diff --git a/matrix/message.py b/matrix/message.py index 7784eb7..9e1e21b 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -1,7 +1,10 @@ from matrix.errors import MatrixError import markdown -from typing import Dict, Optional -from nio import Event +from typing import TYPE_CHECKING, Dict, Optional +from nio import ReactionEvent + +if TYPE_CHECKING: + from matrix.bot import Bot # pragma: no cover class Message: @@ -14,18 +17,19 @@ class Message: :param bot: The bot instance to use for messages. :type bot: Bot """ + MESSAGE_TYPE = "m.room.message" MATRIX_CUSTOM_HTML = "org.matrix.custom.html" TEXT_MESSAGE_TYPE = "m.text" - def __init__(self, bot) -> None: + def __init__(self, bot: "Bot", **kwargs) -> None: self.bot = bot + self.id = kwargs.get("id", None) + self.content = kwargs.get("content", None) + self.sender = kwargs.get("sender", None) async def _send_to_room( - self, - room_id: str, - content: Dict, - message_type: str = MESSAGE_TYPE + self, room_id: str, content: Dict, message_type: str = MESSAGE_TYPE ) -> None: """ Send a message to the Matrix room. @@ -53,7 +57,6 @@ def _make_content( body: str = "", html: Optional[bool] = None, reaction: Optional[bool] = None, - event_id: Optional[str] = None, key: Optional[str] = None, ) -> Dict: """ @@ -65,8 +68,6 @@ def _make_content( :type html: Optional[bool] :param reaction: Wheter to format the context with a reaction event. :type reaction: Optional[bool] - :param event_id: The ID of the event to react to. - :type event_id: Optional[str] :param key: The reaction to the message. :type key: Optional[str] @@ -84,18 +85,15 @@ def _make_content( if reaction: base["m.relates_to"] = { - "event_id": event_id, + "event_id": self.id, "key": key, "rel_type": "m.annotation", } return base - async def send( - self, - room_id: str, - message: str, - format_markdown: Optional[bool] = True + async def send_message( + self, room_id: str, message: str, format_markdown: Optional[bool] = True ) -> None: """ Send a message to a Matrix room. @@ -113,28 +111,41 @@ async def send( content=self._make_content(body=message, html=format_markdown), ) - async def send_reaction( - self, room_id: str, event: Event, key: str - ) -> None: + async def send_reaction(self, room_id: str, key: str) -> None: """ Send a reaction to a message from a user in a Matrix room. :param room_id: The ID of the room to send the message to. :type room_id: str - :param event: The event object to react to. - :type event: Event :param key: The reaction to the message. :type key: str """ - if isinstance(event, Event): - event_id = event.event_id - else: - event_id = event - await self._send_to_room( room_id=room_id, - content=self._make_content( - event_id=event_id, key=key, reaction=True - ), + content=self._make_content(key=key, reaction=True), message_type="m.reaction", ) + + @staticmethod + def from_event(bot, event): + """ + Method to construct a Message instance from event. + Support regular message events and reaction events. + """ + if event is None: + return Message(bot=bot) + + if isinstance(event, ReactionEvent): + event_id = event.source["content"]["m.relates_to"]["event_id"] + body = event.source["content"] + else: + event_id = event.event_id + body = event.body + + return Message( + bot=bot, + id=event_id, + content=body, + sender=event.sender, + ) + From e520f403849809325e6f7a2a0d93b72ba57fe83c Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:05:23 -0700 Subject: [PATCH 21/39] added get message from room --- matrix/room.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/matrix/room.py b/matrix/room.py index 0e1f64a..dfcbfa1 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -43,11 +43,24 @@ async def send( :raises MatrixError: If sending the message fails. """ try: - msg = Message(self.bot) + msg = self.get_message(self.bot, event) if key: - await msg.send_reaction(self.room_id, event, key) + await msg.send_reaction(self.room_id, key) else: - await msg.send(self.room_id, message, markdown) + await msg.send_message(self.room_id, message, markdown) + except Exception as e: + raise MatrixError(f"Failed to send message: {e}") + + @staticmethod + def get_message(bot: "Bot", event: Event): + if not event and not bot: + raise MatrixError("Failed to get message.") + + return Message.from_event(bot, event) + + async def react(self, event: Event, key: str) -> None: + try: + await self.send(event=event, key=key) except Exception as e: raise MatrixError(f"Failed to send message: {e}") From 3d4e6b8527ff805435374481cb65f7314067ff31 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:05:59 -0700 Subject: [PATCH 22/39] remove vs code from commit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0a19790..a6b9f82 100644 --- a/.gitignore +++ b/.gitignore @@ -172,3 +172,5 @@ cython_debug/ # PyPI configuration file .pypirc + +.vscode \ No newline at end of file From 1e650c5fe6f7d142e3ca8ee8fb7aa5459718136a Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:12:45 -0700 Subject: [PATCH 23/39] fix import declaration --- examples/reaction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/reaction.py b/examples/reaction.py index b9d6250..0fe49fc 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -1,6 +1,6 @@ -from matrix.bot import Bot +from matrix import Bot -bot = Bot("examples/config.yaml") +bot = Bot("config.yaml") @bot.event From 5b7df41468119ae851d7fb265d7e1132c28f185a Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:17:00 -0700 Subject: [PATCH 24/39] fix import in example --- examples/reaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/reaction.py b/examples/reaction.py index 0fe49fc..e8b93fa 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -1,6 +1,6 @@ from matrix import Bot -bot = Bot("config.yaml") +bot = Bot("examples/config.yaml") @bot.event From 3b0c266612e45a85fbb411eec46d87463cd1ecd4 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:17:39 -0700 Subject: [PATCH 25/39] fix merge conflict --- matrix/room.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/matrix/room.py b/matrix/room.py index f2de768..07345d7 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -2,7 +2,6 @@ from matrix.message import Message from typing import TYPE_CHECKING, Optional from nio import Event -from nio import Event if TYPE_CHECKING: from matrix.bot import Bot # pragma: no cover @@ -28,10 +27,6 @@ async def send( markdown: Optional[bool] = True, event: Optional[Event] = None, key: Optional[str] = None, - message: str = "", - markdown: Optional[bool] = True, - event: Optional[Event] = None, - key: Optional[str] = None, ) -> None: """ Send a message to the room. From 36929c3f11fe110fe308006c5b9601cb26e107cf Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:22:41 -0700 Subject: [PATCH 26/39] fix merge conflict duplcate --- matrix/room.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/matrix/room.py b/matrix/room.py index 07345d7..dfcbfa1 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -93,7 +93,6 @@ async def ban_user( :type user_id: str :param reason: The reason to ban the user. :type reason: Optional[str] - :type reason: Optional[str] :raises MatrixError: If banning the user fails. """ @@ -137,7 +136,6 @@ async def kick_user( :type user_id: str :param reason: The reason to kick the user. :type reason: Optional[str] - :type reason: Optional[str] :raises MatrixError: If kicking the user fails. """ From 5d3bbe173cf707765e7d55289ed41d4bcde12968 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:29:50 -0700 Subject: [PATCH 27/39] Added additional example for reacting to emoji --- examples/reaction.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/reaction.py b/examples/reaction.py index e8b93fa..48f8ff8 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -29,9 +29,13 @@ async def on_react(room, event): and reacts based on the reaction emoji. """ room = bot.get_room(room.room_id) + emoji = event.key - if event.key == "🙏": + if emoji == "🙏": await room.react(event, "hi") + if emoji == "❤️": + await room.react(event, "❤️") + bot.start() From 3573f8bb1df14feeae367fe9ca0646ac29b09df5 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:35:04 -0700 Subject: [PATCH 28/39] fix unit test for send message and send reaction in Message class --- tests/test_message.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_message.py b/tests/test_message.py index 5d0b630..bf95fff 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -36,7 +36,7 @@ async def test_send_message_success(message_default): room_id = "!room:id" message = "Hello, world!" - await message_default.send(room_id, message) + await message_default.send_message(room_id, message) message_default.bot.client.room_send.assert_awaited_once() @@ -49,7 +49,7 @@ async def test_send_message_failure(message_default): "Failed to send message" ) with pytest.raises(MatrixError, match="Failed to send message"): - await message_default.send(room_id, message) + await message_default.send_message(room_id, message) def test_make_content_with_html(message_default): @@ -76,7 +76,7 @@ def test_make_content_without_html(message_default): async def test_send_reaction_success(message_default, event): room_id = "!room:id" - await message_default.send_reaction(room_id, event, "hi") + await message_default.send_reaction(room_id, "hi") message_default.bot.client.room_send.assert_awaited_once() @@ -88,4 +88,4 @@ async def test_send_reaction_failure(message_default, event): "Failed to send message" ) with pytest.raises(MatrixError, match="Failed to send message"): - await message_default.send_reaction(room_id, event, "🙏") + await message_default.send_reaction(room_id, "🙏") From 53e4923d30a9601d5119863366086a562f521ec4 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 10 Jul 2025 18:36:50 -0700 Subject: [PATCH 29/39] fix formatting to make mypy happy --- matrix/message.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/matrix/message.py b/matrix/message.py index 9e1e21b..daabe26 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -93,7 +93,10 @@ def _make_content( return base async def send_message( - self, room_id: str, message: str, format_markdown: Optional[bool] = True + self, + room_id: str, + message: str, + format_markdown: Optional[bool] = True ) -> None: """ Send a message to a Matrix room. From b849b0be6c7f09e87eabc89b36a587ef6b7f7cb8 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 18 Dec 2025 13:48:55 -0800 Subject: [PATCH 30/39] add type hints and docstrings for get_message and react methods --- matrix/room.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/matrix/room.py b/matrix/room.py index fc9039b..3e5df5b 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -52,13 +52,26 @@ async def send( raise MatrixError(f"Failed to send message: {e}") @staticmethod - def get_message(bot: "Bot", event: Event): + def get_message(bot: "Bot", event: Event) -> Message: + """ + Get a Message instance from an event. + :param bot: The bot instance to use for messages. + :param event: The event object to construct the message from. + + :return: The constructed Message instance. + """ if not event and not bot: raise MatrixError("Failed to get message.") return Message.from_event(bot, event) async def react(self, event: Event, key: str) -> None: + """ + Send a reaction to a message in the room. + + :param event: The event to react to. + :param key: The reaction to the message. + """ try: await self.send(event=event, key=key) except Exception as e: From 909cbd2b79b98f95337c68094cb5df63d8501af2 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 18 Dec 2025 13:49:49 -0800 Subject: [PATCH 31/39] refactor Message class constructor and update docstrings for clarity --- matrix/message.py | 51 ++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index 4696fdd..9805ee1 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -5,6 +5,7 @@ if TYPE_CHECKING: from matrix.bot import Bot # pragma: no cover + from nio import Event # pragma: no cover class Message: @@ -15,33 +16,37 @@ class Message: formatting the message content as either plain text or HTML. :param bot: The bot instance to use for messages. - :type bot: Bot + :param id: The unique identifier of the message event. + :param content: The content of the message. + :param sender: The sender of the message. """ + MESSAGE_TYPE = "m.room.message" MATRIX_CUSTOM_HTML = "org.matrix.custom.html" TEXT_MESSAGE_TYPE = "m.text" - def __init__(self, bot: "Bot", **kwargs) -> None: + def __init__( + self, + bot: "Bot", + *, + id: Optional[str] = None, + content: Optional[str] = None, + sender: Optional[str] = None, + ) -> None: self.bot = bot - self.id = kwargs.get("id", None) - self.content = kwargs.get("content", None) - self.sender = kwargs.get("sender", None) + self.id = id + self.content = content + self.sender = sender async def _send_to_room( - self, - room_id: str, - content: Dict, - message_type: str = MESSAGE_TYPE + self, room_id: str, content: Dict, message_type: str = MESSAGE_TYPE ) -> None: """ Send a message to the Matrix room. :param room_id: The ID of the room to send the message to. - :type room_id: str :param content: The matrix JSON payload. - :type content: Dict :param message_type: The type of the message. - :type message_type: str :raise MatrixError: If sending the message fails. """ @@ -65,13 +70,9 @@ def _make_content( Create the content dictionary for a message. :param body: The body of the message. - :type body: str :param html: Wheter to format the message as HTML. - :type html: Optional[bool] :param reaction: Wheter to format the context with a reaction event. - :type reaction: Optional[bool] :param key: The reaction to the message. - :type key: Optional[str] :return: The content of the dictionary. """ @@ -95,21 +96,15 @@ def _make_content( return base async def send_message( - self, - room_id: str, - message: str, - format_markdown: Optional[bool] = True + self, room_id: str, message: str, format_markdown: Optional[bool] = True ) -> None: """ Send a message to a Matrix room. :param room_id: The ID of the room to send the message to. - :type room_id: str :param message: The message to send. - :type message: str :param format_markdown: Whether to format the message as Markdown (default to True). - :type format_markdown: Optional[bool] """ await self._send_to_room( room_id=room_id, @@ -121,9 +116,7 @@ async def send_reaction(self, room_id: str, key: str) -> None: Send a reaction to a message from a user in a Matrix room. :param room_id: The ID of the room to send the message to. - :type room_id: str :param key: The reaction to the message. - :type key: str """ await self._send_to_room( room_id=room_id, @@ -132,10 +125,15 @@ async def send_reaction(self, room_id: str, key: str) -> None: ) @staticmethod - def from_event(bot, event): + def from_event(bot: "Bot", event: Optional[Event] = None) -> Message: """ Method to construct a Message instance from event. Support regular message events and reaction events. + + :param bot: The bot instance to use for messages. + :param event: The event object to construct the message from. + + :return: The constructed Message instance. """ if event is None: return Message(bot=bot) @@ -153,4 +151,3 @@ def from_event(bot, event): content=body, sender=event.sender, ) - From ab2498aa59a89563a37f2ab37bddbc4f4c4be3a5 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 18 Dec 2025 13:51:52 -0800 Subject: [PATCH 32/39] remove type hints from docstrings in Room class for cleaner documentation. The reason is because we are using type hints which having it also in the docstring just duplicate unecessarly. --- matrix/room.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/matrix/room.py b/matrix/room.py index 3e5df5b..a97d419 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -12,9 +12,7 @@ class Room: Represents a Matrix room and provides methods to interact with it. :param room_id: The unique identifier of the room. - :type room_id: str :param bot: The bot instance used to send messages. - :type bot: Bot """ def __init__(self, room_id: str, bot: "Bot") -> None: @@ -32,13 +30,9 @@ async def send( Send a message to the room. :param message: The message to send. - :type message: str :param markdown: Whether to format the message as Markdown. - :type markdown: Optional[bool] :param event: An event object to react to. - :type event: Optional[Event] :param key: The reaction to the message. - :type key: Optional[str] :raises MatrixError: If sending the message fails. """ @@ -96,9 +90,7 @@ async def ban_user(self, user_id: str, reason: Optional[str] = None) -> None: Ban a user from a room. :param user_id: The ID of the user to ban of the room. - :type user_id: str :param reason: The reason to ban the user. - :type reason: Optional[str] :raises MatrixError: If banning the user fails. """ @@ -115,7 +107,6 @@ async def unban_user(self, user_id: str) -> None: Unban a user from a room. :param user_id: The ID of the user to unban of the room. - :type user_id: str :raises MatrixError: If unbanning the user fails. """ @@ -130,9 +121,7 @@ async def kick_user(self, user_id: str, reason: Optional[str] = None) -> None: Kick a user from a room. :param user_id: The ID of the user to kick of the room. - :type user_id: str :param reason: The reason to kick the user. - :type reason: Optional[str] :raises MatrixError: If kicking the user fails. """ From d069c9993f739b6bbb475dfa1f89795c9c1aa399 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 18 Dec 2025 14:18:13 -0800 Subject: [PATCH 33/39] refactor Message class to handle reactions using Event type --- matrix/message.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index 9805ee1..1f6da4e 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -1,11 +1,10 @@ from matrix.errors import MatrixError import markdown from typing import TYPE_CHECKING, Dict, Optional -from nio import ReactionEvent +from nio import Event if TYPE_CHECKING: from matrix.bot import Bot # pragma: no cover - from nio import Event # pragma: no cover class Message: @@ -138,7 +137,7 @@ def from_event(bot: "Bot", event: Optional[Event] = None) -> Message: if event is None: return Message(bot=bot) - if isinstance(event, ReactionEvent): + if isinstance(event, Event) and event.source["type"] == "m.reaction": event_id = event.source["content"]["m.relates_to"]["event_id"] body = event.source["content"] else: From 9b3ea4823ad24111f4584efa17494ed2666fe46d Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 18 Dec 2025 14:21:02 -0800 Subject: [PATCH 34/39] update from_event method to return Message type hint for better clarity --- matrix/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix/message.py b/matrix/message.py index 1f6da4e..d8ac6cc 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -124,7 +124,7 @@ async def send_reaction(self, room_id: str, key: str) -> None: ) @staticmethod - def from_event(bot: "Bot", event: Optional[Event] = None) -> Message: + def from_event(bot: "Bot", event: Optional[Event] = None) -> "Message": """ Method to construct a Message instance from event. Support regular message events and reaction events. From e5b0102d3c02f28f845b984282f593af4a55cfc1 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 20 Dec 2025 15:04:34 -0800 Subject: [PATCH 35/39] enforce required event in from_event + enforce self.id non null --- matrix/message.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index d8ac6cc..55f8bc3 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -1,4 +1,4 @@ -from matrix.errors import MatrixError +from matrix.errors import MatrixError, MissingArgumentError import markdown from typing import TYPE_CHECKING, Dict, Optional from nio import Event @@ -29,11 +29,14 @@ def __init__( bot: "Bot", *, id: Optional[str] = None, + event: Optinal[str] = None, content: Optional[str] = None, sender: Optional[str] = None, ) -> None: self.bot = bot self.id = id + if not self.id and event: + self.id = event.event_id self.content = content self.sender = sender @@ -75,6 +78,8 @@ def _make_content( :return: The content of the dictionary. """ + if self.id is None: + raise ValueError("id cannot be None") base: Dict = { "msgtype": self.TEXT_MESSAGE_TYPE, @@ -124,7 +129,7 @@ async def send_reaction(self, room_id: str, key: str) -> None: ) @staticmethod - def from_event(bot: "Bot", event: Optional[Event] = None) -> "Message": + def from_event(bot: "Bot", event: Event) -> "Message": """ Method to construct a Message instance from event. Support regular message events and reaction events. @@ -133,9 +138,10 @@ def from_event(bot: "Bot", event: Optional[Event] = None) -> "Message": :param event: The event object to construct the message from. :return: The constructed Message instance. + :raise MissingArgumentError: If event is None. """ if event is None: - return Message(bot=bot) + raise MissingArgumentError("event cannot be None") if isinstance(event, Event) and event.source["type"] == "m.reaction": event_id = event.source["content"]["m.relates_to"]["event_id"] From dafcbd6dceb53a6dfad753b8494e892be6bc298c Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 20 Dec 2025 15:04:51 -0800 Subject: [PATCH 36/39] enforce required Event in Room.send --- matrix/room.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix/room.py b/matrix/room.py index a97d419..d3142c7 100644 --- a/matrix/room.py +++ b/matrix/room.py @@ -22,8 +22,9 @@ def __init__(self, room_id: str, bot: "Bot") -> None: async def send( self, message: str = "", + *, + event: Event, markdown: Optional[bool] = True, - event: Optional[Event] = None, key: Optional[str] = None, ) -> None: """ From 07b4598598f7edc82db74f79bc32668e6ed4047d Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 20 Dec 2025 15:05:05 -0800 Subject: [PATCH 37/39] added comment todo for upcoming refactor --- matrix/context.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/matrix/context.py b/matrix/context.py index 385d71b..cfcd84a 100644 --- a/matrix/context.py +++ b/matrix/context.py @@ -79,6 +79,12 @@ async def reply(self, message: str) -> None: """ try: + # @todo When Message instance is refactored, refactor this to pass + # the room_id to the message and remove it from `send_message` method. + """example: + c = Message(self.bot, self.room_id) + await c.send_message(message=message) + """ c = Message(self.bot) await c.send_message(room_id=self.room_id, message=message) except Exception as e: From 68ae7f984c08aeb5730527565f3aaa8df2cd3ee6 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 20 Dec 2025 15:05:20 -0800 Subject: [PATCH 38/39] added event to room.send as now it is required --- examples/reaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/reaction.py b/examples/reaction.py index 5276752..e457b4b 100644 --- a/examples/reaction.py +++ b/examples/reaction.py @@ -20,7 +20,7 @@ async def on_message(room: Room, event: Event) -> None: if event.body.lower().startswith("❤️"): # Or directly reply as a message instead of a reaction - await room.send(message="❤️") + await room.send(message="❤️", event=event) @bot.event From 26c95c326f18b93bdef2e62ac80685764ed362cb Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 20 Dec 2025 20:19:43 -0800 Subject: [PATCH 39/39] mypy ffix --- matrix/message.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix/message.py b/matrix/message.py index 55f8bc3..5f08241 100644 --- a/matrix/message.py +++ b/matrix/message.py @@ -1,4 +1,4 @@ -from matrix.errors import MatrixError, MissingArgumentError +from matrix.errors import MatrixError import markdown from typing import TYPE_CHECKING, Dict, Optional from nio import Event @@ -29,7 +29,7 @@ def __init__( bot: "Bot", *, id: Optional[str] = None, - event: Optinal[str] = None, + event: Optional[Event] = None, content: Optional[str] = None, sender: Optional[str] = None, ) -> None: @@ -141,7 +141,7 @@ def from_event(bot: "Bot", event: Event) -> "Message": :raise MissingArgumentError: If event is None. """ if event is None: - raise MissingArgumentError("event cannot be None") + raise ValueError("event cannot be None") if isinstance(event, Event) and event.source["type"] == "m.reaction": event_id = event.source["content"]["m.relates_to"]["event_id"]