From 9930725e2af78159c01904e31a3b6fdf358fdba5 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi Date: Sat, 9 Jan 2021 17:48:56 +0100 Subject: [PATCH 1/3] Add New Shortcuts to Chat (#2291) * Add shortcuts * Add a note --- telegram/chat.py | 92 +++++++++++++++++++++++++++++++++++++++ telegram/user.py | 2 +- telegram/utils/helpers.py | 4 +- tests/test_chat.py | 51 ++++++++++++++++++++++ 4 files changed, 146 insertions(+), 3 deletions(-) diff --git a/telegram/chat.py b/telegram/chat.py index e049f0114a4..d9fbe6f761d 100644 --- a/telegram/chat.py +++ b/telegram/chat.py @@ -189,6 +189,24 @@ def __init__( self.bot = bot self._id_attrs = (self.id,) + @property + def full_name(self) -> Optional[str]: + """ + :obj:`str`: Convenience property. If :attr:`first_name` is not :obj:`None` gives, + :attr:`first_name` followed by (if available) :attr:`last_name`. + + Note: + :attr:`full_name` will always be :obj:`None`, if the chat is a (super)group or + channel. + + .. versionadded:: 13.2 + """ + if not self.first_name: + return None + if self.last_name: + return f'{self.first_name} {self.last_name}' + return self.first_name + @property def link(self) -> Optional[str]: """:obj:`str`: Convenience property. If the chat has a :attr:`username`, returns a t.me @@ -350,6 +368,80 @@ def unban_member( only_if_banned=only_if_banned, ) + def promote_member( + self, + user_id: Union[str, int], + can_change_info: bool = None, + can_post_messages: bool = None, + can_edit_messages: bool = None, + can_delete_messages: bool = None, + can_invite_users: bool = None, + can_restrict_members: bool = None, + can_pin_messages: bool = None, + can_promote_members: bool = None, + timeout: float = None, + api_kwargs: JSONDict = None, + is_anonymous: bool = None, + ) -> bool: + """Shortcut for:: + + bot.promote_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.promote_chat_member`. + + .. versionadded:: 13.2 + + Returns: + :obj:`bool`: If the action was sent successfully. + + """ + return self.bot.promote_chat_member( + chat_id=self.id, + user_id=user_id, + can_change_info=can_change_info, + can_post_messages=can_post_messages, + can_edit_messages=can_edit_messages, + can_delete_messages=can_delete_messages, + can_invite_users=can_invite_users, + can_restrict_members=can_restrict_members, + can_pin_messages=can_pin_messages, + can_promote_members=can_promote_members, + timeout=timeout, + api_kwargs=api_kwargs, + is_anonymous=is_anonymous, + ) + + def restrict_member( + self, + user_id: Union[str, int], + permissions: ChatPermissions, + until_date: Union[int, datetime] = None, + timeout: float = None, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.restrict_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.restrict_chat_member`. + + .. versionadded:: 13.2 + + Returns: + :obj:`bool`: If the action was sent successfully. + + """ + return self.bot.restrict_chat_member( + chat_id=self.id, + user_id=user_id, + permissions=permissions, + until_date=until_date, + timeout=timeout, + api_kwargs=api_kwargs, + ) + def set_permissions( self, permissions: ChatPermissions, diff --git a/telegram/user.py b/telegram/user.py index 404b30026fb..e0e6642978e 100644 --- a/telegram/user.py +++ b/telegram/user.py @@ -135,7 +135,7 @@ def full_name(self) -> str: available) :attr:`last_name`.""" if self.last_name: - return u'{} {}'.format(self.first_name, self.last_name) + return f'{self.first_name} {self.last_name}' return self.first_name @property diff --git a/telegram/utils/helpers.py b/telegram/utils/helpers.py index 8e9a82c7975..522a9940488 100644 --- a/telegram/utils/helpers.py +++ b/telegram/utils/helpers.py @@ -317,7 +317,7 @@ def mention_html(user_id: Union[int, str], name: str) -> str: Returns: :obj:`str`: The inline mention for the user as html. """ - return u'{}'.format(user_id, escape(name)) + return f'{escape(name)}' def mention_markdown(user_id: Union[int, str], name: str, version: int = 1) -> str: @@ -331,7 +331,7 @@ def mention_markdown(user_id: Union[int, str], name: str, version: int = 1) -> s Returns: :obj:`str`: The inline mention for the user as markdown. """ - return u'[{}](tg://user?id={})'.format(escape_markdown(name, version=version), user_id) + return f'[{escape_markdown(name, version=version)}](tg://user?id={user_id})' def effective_message_type(entity: Union['Message', 'Update']) -> Optional[str]: diff --git a/tests/test_chat.py b/tests/test_chat.py index f980eb1ee82..02453109203 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -112,6 +112,19 @@ def test_link(self, chat): chat.username = None assert chat.link is None + def test_full_name(self): + chat = Chat( + id=1, type=Chat.PRIVATE, first_name=u'first\u2022name', last_name=u'last\u2022name' + ) + assert chat.full_name == u'first\u2022name last\u2022name' + chat = Chat(id=1, type=Chat.PRIVATE, first_name=u'first\u2022name') + assert chat.full_name == u'first\u2022name' + chat = Chat( + id=1, + type=Chat.PRIVATE, + ) + assert chat.full_name is None + def test_send_action(self, monkeypatch, chat): send_chat_action = chat.bot.send_chat_action @@ -211,6 +224,44 @@ def make_assertion(*_, **kwargs): monkeypatch.setattr(chat.bot, 'unban_chat_member', make_assertion) assert chat.unban_member(user_id=42, only_if_banned=only_if_banned) + @pytest.mark.parametrize('is_anonymous', [True, False, None]) + def test_promote_member(self, monkeypatch, chat, is_anonymous): + promote_chat_member = chat.bot.promote_chat_member + + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == chat.id + user_id = kwargs['user_id'] == 42 + o_i_b = kwargs.get('is_anonymous', None) == is_anonymous + return ( + chat_id and user_id and o_i_b and check_shortcut_call(kwargs, promote_chat_member) + ) + + assert check_shortcut_signature( + Chat.promote_member, Bot.promote_chat_member, ['chat_id'], [] + ) + + monkeypatch.setattr(chat.bot, 'promote_chat_member', make_assertion) + assert chat.promote_member(user_id=42, is_anonymous=is_anonymous) + + def test_restrict_member(self, monkeypatch, chat): + restrict_chat_member = chat.bot.restrict_chat_member + permissions = ChatPermissions(True, False, True, False, True, False, True, False) + + def make_assertion(*_, **kwargs): + chat_id = kwargs['chat_id'] == chat.id + user_id = kwargs['user_id'] == 42 + o_i_b = kwargs.get('permissions', None) == permissions + return ( + chat_id and user_id and o_i_b and check_shortcut_call(kwargs, restrict_chat_member) + ) + + assert check_shortcut_signature( + Chat.restrict_member, Bot.restrict_chat_member, ['chat_id'], [] + ) + + monkeypatch.setattr(chat.bot, 'restrict_chat_member', make_assertion) + assert chat.restrict_member(user_id=42, permissions=permissions) + def test_set_permissions(self, monkeypatch, chat): set_chat_permissions = chat.bot.set_chat_permissions From 0c9915243df7fabe70d827250118a975d705fc6b Mon Sep 17 00:00:00 2001 From: zeshuaro Date: Sun, 10 Jan 2021 06:05:58 +1100 Subject: [PATCH 2/3] Add run_async Parameter to ConversationHandler (#2292) * Add run_async parameter * Update docstring * Update test to explicitly specify parameter * Fix test job queue * Add version added tag to docs * Update docstring Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Doc nitpicking Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: Hinrich Mahler --- telegram/ext/conversationhandler.py | 22 +++++++++++++++++-- tests/test_conversationhandler.py | 33 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/telegram/ext/conversationhandler.py b/telegram/ext/conversationhandler.py index fdcf8748b5a..2bee77406f9 100644 --- a/telegram/ext/conversationhandler.py +++ b/telegram/ext/conversationhandler.py @@ -136,6 +136,15 @@ class ConversationHandler(Handler[Update]): map_to_parent (Dict[:obj:`object`, :obj:`object`], optional): A :obj:`dict` that can be used to instruct a nested conversationhandler to transition into a mapped state on its parent conversationhandler in place of a specified nested state. + run_async (:obj:`bool`, optional): Pass :obj:`True` to *override* the + :attr:`Handler.run_async` setting of all handlers (in :attr:`entry_points`, + :attr:`states` and :attr:`fallbacks`). + + Note: + If set to :obj:`True`, you should not pass a handler instance, that needs to be + run synchronously in another context. + + .. versionadded:: 13.2 Raises: ValueError @@ -168,6 +177,10 @@ class ConversationHandler(Handler[Update]): map_to_parent (Dict[:obj:`object`, :obj:`object`]): Optional. A :obj:`dict` that can be used to instruct a nested conversationhandler to transition into a mapped state on its parent conversationhandler in place of a specified nested state. + run_async (:obj:`bool`): If :obj:`True`, will override the + :attr:`Handler.run_async` setting of all internal handlers on initialization. + + .. versionadded:: 13.2 """ @@ -192,8 +205,9 @@ def __init__( name: str = None, persistent: bool = False, map_to_parent: Dict[object, object] = None, + run_async: bool = False, ): - self.run_async = False + self.run_async = run_async self._entry_points = entry_points self._states = states @@ -229,7 +243,7 @@ def __init__( "since message IDs are not globally unique." ) - all_handlers = list() + all_handlers: List[Handler] = list() all_handlers.extend(entry_points) all_handlers.extend(fallbacks) @@ -263,6 +277,10 @@ def __init__( ) break + if self.run_async: + for handler in all_handlers: + handler.run_async = True + @property def entry_points(self) -> List[Handler]: return self._entry_points diff --git a/tests/test_conversationhandler.py b/tests/test_conversationhandler.py index 8436d2c491a..4bb36c644e5 100644 --- a/tests/test_conversationhandler.py +++ b/tests/test_conversationhandler.py @@ -1429,3 +1429,36 @@ def test_callback(u, c): assert self.current_state[user1.id] == self.STOPPING assert handler.conversations.get((0, user1.id)) is None assert not self.test_flag + + def test_conversation_handler_run_async_true(self, dp): + conv_handler = ConversationHandler( + entry_points=self.entry_points, + states=self.states, + fallbacks=self.fallbacks, + run_async=True, + ) + + all_handlers = conv_handler.entry_points + conv_handler.fallbacks + for state_handlers in conv_handler.states.values(): + all_handlers += state_handlers + + for handler in all_handlers: + assert handler.run_async + + def test_conversation_handler_run_async_false(self, dp): + conv_handler = ConversationHandler( + entry_points=[CommandHandler('start', self.start_end, run_async=True)], + states=self.states, + fallbacks=self.fallbacks, + run_async=False, + ) + + for handler in conv_handler.entry_points: + assert handler.run_async + + all_handlers = conv_handler.fallbacks + for state_handlers in conv_handler.states.values(): + all_handlers += state_handlers + + for handler in all_handlers: + assert not handler.run_async.value From 8c842a872b23cd724110dc491e70e0bb9a59b87f Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Sun, 10 Jan 2021 16:05:29 +0530 Subject: [PATCH 3/3] Fix rendering in messageentity --- telegram/messageentity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram/messageentity.py b/telegram/messageentity.py index c92a98e0f2d..04947cb9563 100644 --- a/telegram/messageentity.py +++ b/telegram/messageentity.py @@ -33,7 +33,7 @@ class MessageEntity(TelegramObject): usernames, URLs, etc. Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`offset` and :attr`length` are equal. + considered equal, if their :attr:`type`, :attr:`offset` and :attr:`length` are equal. Args: type (:obj:`str`): Type of the entity. Can be mention (@username), hashtag, bot_command, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy