Message: Add unreact() method - #115
Conversation
Signed-off-by: anay <agarodia98@gmail.com>
| """ | ||
| reaction_event_id = None | ||
| try: | ||
| async for event in self.client.room_get_event_relations( |
There was a problem hiding this comment.
I'm not a big fan of duplicating the logic here that we already have in fetch_reactions. However, we can't use fetch_reactions directly because it doesn't contain the information we need (event_id). There's a couple of solutions but I believe the simplest solution for now is extracting the iteration over reactions in a private helper method:
# types.py
@dataclass
class ReactionEvent:
emoji: str
sender: str
event_id: str
# message.py (message class)
async def _iter_reaction_events(self) -> AsyncIterator[ReactionEvent]:
"""Yield (emoji, sender, event_id) for each reaction relation on this message."""
try:
async for event in self.client.room_get_event_relations(
room_id=self.room.room_id,
event_id=self.event_id,
):
emoji = getattr(event, "key", None)
sender = getattr(event, "sender", None)
event_id = getattr(event, "event_id", None)
if emoji and sender and event_id:
yield ReactionEvent(emoji=emoji, sender=sender, event_id=event_id)
except Exception as e:
raise MatrixError(f"Failed to fetch reactions: {e}")And then you can use it in both fetch_reactions and unreact:
# message.py (message class)
async def fetch_reactions(self) -> list[Reaction]:
"""..."""
raw: dict[str, list[str]] = {}
async for reaction_event in self._iter_reaction_events():
raw.setdefault(reaction_event.emoji, []).append(reaction_event.sender)
return [Reaction(key=emoji, senders=senders) for emoji, senders in raw.items()]
...
async def unreact(self, emoji: str) -> None:
"""..."""
reaction_event_id = None
async for reaction_event in self._iter_reaction_events():
if reaction_event.emoji == emoji and reaction_event.sender == self.client.user_id:
reaction_event_id = reaction_event.event_id
break
if reaction_event_id is None:
return
await matrix_call(
self.client.room_redact(
room_id=self.room.room_id,
event_id=reaction_event_id,
),
error_message="Failed to remove reaction",
)Ideally, we would bring changes to the existing Reaction dataclass so that instead of having sender we have list of ReactionEvent but it might be too out of scope of this PR so it's not required. The changes above are enough for now.
| if reaction_event_id: | ||
| break | ||
| except Exception as e: | ||
| raise MatrixError(f"Failed to remove reaction: {e}") from e |
There was a problem hiding this comment.
Although this will go away with the changes from the comment above, the exception message is identical to the next matrix_call's message which could lead to confusing
There was a problem hiding this comment.
Good test coverage overall, but there's a small gap: unreact wraps the relation loop, but none of the three tests actually test the possible exception raising from there.
Something like:
@pytest.mark.asyncio
async def test_unreact_with_relations_error__expect_matrix_error(message, client):
async def mock_relations(*args, **kwargs):
raise Exception("Network error")
yield
client.room_get_event_relations = mock_relations
with pytest.raises(MatrixError, match="Failed to fetch reactions: ..."):
await message.unreact("👍")This is similar to test_fetch_reactions_with_error__expect_matrix_error
Signed-off-by: anay <agarodia98@gmail.com>
|
Addressed all requested changes in a2f9b50:
Full |
There was a problem hiding this comment.
It seems like editor changed some whitespace or something, but it doesn't seem to change anything. Just be careful with that in the future.
PenguinBoi12
left a comment
There was a problem hiding this comment.
LGTM 🦭
Thanks for the contribution and don't forget to ⭐
* feat(message): add unreact method Signed-off-by: anay <agarodia98@gmail.com> * refactor(message): share reaction iteration Signed-off-by: anay <agarodia98@gmail.com> --------- Signed-off-by: anay <agarodia98@gmail.com>
Summary
Message.unreact(emoji)to locate the client's matching reaction event and redact itMatrixErrorwith the requested messageVerification
black --fast --check matrix/ tests/mypy matrix/pytest tests/test_message.py -q(32 passed)pytest -q(354 passed)Closes #114