Add Parameter chat_id to ChatMemberHandler (#4290)

This commit is contained in:
Trijeet Modak 2024-06-06 21:01:45 +05:30 committed by GitHub
parent cf728496e4
commit 9e70ac8b7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 86 additions and 11 deletions

View file

@ -21,8 +21,9 @@ from typing import Final, Optional, TypeVar
from telegram import Update from telegram import Update
from telegram._utils.defaultvalue import DEFAULT_TRUE from telegram._utils.defaultvalue import DEFAULT_TRUE
from telegram._utils.types import DVType from telegram._utils.types import SCT, DVType
from telegram.ext._handlers.basehandler import BaseHandler from telegram.ext._handlers.basehandler import BaseHandler
from telegram.ext._utils._update_parsing import parse_chat_id
from telegram.ext._utils.types import CCT, HandlerCallback from telegram.ext._utils.types import CCT, HandlerCallback
RT = TypeVar("RT") RT = TypeVar("RT")
@ -58,6 +59,9 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
:meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`. :meth:`telegram.ext.Application.process_update`. Defaults to :obj:`True`.
.. seealso:: :wiki:`Concurrency` .. seealso:: :wiki:`Concurrency`
chat_id (:obj:`int` | Collection[:obj:`int`], optional): Filters chat member updates from
specified chat ID(s) only.
.. versionadded:: NEXT.VERSION
Attributes: Attributes:
callback (:term:`coroutine function`): The callback function for this handler. callback (:term:`coroutine function`): The callback function for this handler.
@ -70,7 +74,10 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
""" """
__slots__ = ("chat_member_types",) __slots__ = (
"_chat_ids",
"chat_member_types",
)
MY_CHAT_MEMBER: Final[int] = -1 MY_CHAT_MEMBER: Final[int] = -1
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`.""" """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`."""
CHAT_MEMBER: Final[int] = 0 CHAT_MEMBER: Final[int] = 0
@ -84,10 +91,12 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
callback: HandlerCallback[Update, CCT, RT], callback: HandlerCallback[Update, CCT, RT],
chat_member_types: int = MY_CHAT_MEMBER, chat_member_types: int = MY_CHAT_MEMBER,
block: DVType[bool] = DEFAULT_TRUE, block: DVType[bool] = DEFAULT_TRUE,
chat_id: Optional[SCT[int]] = None,
): ):
super().__init__(callback, block=block) super().__init__(callback, block=block)
self.chat_member_types: Optional[int] = chat_member_types self.chat_member_types: Optional[int] = chat_member_types
self._chat_ids = parse_chat_id(chat_id)
def check_update(self, update: object) -> bool: def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handler's :attr:`callback`. """Determines whether an update should be passed to this handler's :attr:`callback`.
@ -99,12 +108,18 @@ class ChatMemberHandler(BaseHandler[Update, CCT]):
:obj:`bool` :obj:`bool`
""" """
if isinstance(update, Update): if not isinstance(update, Update):
if not (update.my_chat_member or update.chat_member): return False
return False if not (update.my_chat_member or update.chat_member):
if self.chat_member_types == self.ANY_CHAT_MEMBER: return False
return True if (
if self.chat_member_types == self.CHAT_MEMBER: self._chat_ids
return bool(update.chat_member) and update.effective_chat
return bool(update.my_chat_member) and update.effective_chat.id not in self._chat_ids
return False ):
return False
if self.chat_member_types == self.ANY_CHAT_MEMBER:
return True
if self.chat_member_types == self.CHAT_MEMBER:
return bool(update.chat_member)
return bool(update.my_chat_member)

View file

@ -144,6 +144,66 @@ class TestChatMemberHandler:
await app.process_update(chat_member) await app.process_update(chat_member)
assert self.test_flag == result_2 assert self.test_flag == result_2
@pytest.mark.parametrize(
argnames=["allowed_types", "chat_id", "expected"],
argvalues=[
(ChatMemberHandler.MY_CHAT_MEMBER, None, (True, False)),
(ChatMemberHandler.CHAT_MEMBER, None, (False, True)),
(ChatMemberHandler.ANY_CHAT_MEMBER, None, (True, True)),
(ChatMemberHandler.MY_CHAT_MEMBER, 1, (True, False)),
(ChatMemberHandler.CHAT_MEMBER, 1, (False, True)),
(ChatMemberHandler.ANY_CHAT_MEMBER, 1, (True, True)),
(ChatMemberHandler.MY_CHAT_MEMBER, [1], (True, False)),
(ChatMemberHandler.CHAT_MEMBER, [1], (False, True)),
(ChatMemberHandler.ANY_CHAT_MEMBER, [1], (True, True)),
(ChatMemberHandler.MY_CHAT_MEMBER, 2, (False, False)),
(ChatMemberHandler.CHAT_MEMBER, 2, (False, False)),
(ChatMemberHandler.ANY_CHAT_MEMBER, 2, (False, False)),
(ChatMemberHandler.MY_CHAT_MEMBER, [2], (False, False)),
(ChatMemberHandler.CHAT_MEMBER, [2], (False, False)),
(ChatMemberHandler.ANY_CHAT_MEMBER, [2], (False, False)),
],
ids=[
"MY_CHAT_MEMBER",
"CHAT_MEMBER",
"ANY_CHAT_MEMBER",
"MY_CHAT_MEMBER, CHAT=1 ",
"CHAT_MEMBER, CHAT=1",
"ANY_CHAT_MEMBER, CHAT=1",
"MY_CHAT_MEMBER, CHAT=[1] ",
"CHAT_MEMBER, CHAT=[1]",
"ANY_CHAT_MEMBER, CHAT=[1]",
"MY_CHAT_MEMBER, CHAT=2 ",
"CHAT_MEMBER, CHAT=2",
"ANY_CHAT_MEMBER, CHAT=2",
"MY_CHAT_MEMBER, CHAT=[2] ",
"CHAT_MEMBER, CHAT=[2]",
"ANY_CHAT_MEMBER, CHAT=[2]",
],
)
async def test_chat_member_types_with_chat_id(
self, app, chat_member_updated, chat_member, expected, allowed_types, chat_id
):
result_1, result_2 = expected
handler = ChatMemberHandler(
self.callback, chat_member_types=allowed_types, chat_id=chat_id
)
app.add_handler(handler)
async with app:
assert handler.check_update(chat_member) == result_1
await app.process_update(chat_member)
assert self.test_flag == result_1
self.test_flag = False
chat_member.my_chat_member = None
chat_member.chat_member = chat_member_updated
assert handler.check_update(chat_member) == result_2
await app.process_update(chat_member)
assert self.test_flag == result_2
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = ChatMemberHandler(self.callback) handler = ChatMemberHandler(self.callback)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)