Add pattern Argument to ChosenInlineResultHandler (#2517)

* Feat: add pattern arg to ChosenInlineResultHandler

* Fix: remove unnecessary if clause

the attribute must be present, since it's not optional.

* Fix: wrong type documentation

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>

* Fix: Addressing code review

small documentation fixes, and moving one test.

* Fix: link to matches

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>

* Fix: also link here

Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>
This commit is contained in:
Poolitzer 2021-05-19 10:32:11 +02:00 committed by GitHub
parent 7d0fb85c8c
commit 8b0d2e5f75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 3 deletions

View file

@ -17,15 +17,19 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the ChosenInlineResultHandler class."""
from typing import Optional, TypeVar, Union
import re
from typing import Optional, TypeVar, Union, Callable, TYPE_CHECKING, Pattern, Match, cast
from telegram import Update
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
from .handler import Handler
RT = TypeVar('RT')
if TYPE_CHECKING:
from telegram.ext import CallbackContext, Dispatcher
class ChosenInlineResultHandler(Handler[Update]):
"""Handler class to handle Telegram updates that contain a chosen inline result.
@ -70,6 +74,12 @@ class ChosenInlineResultHandler(Handler[Update]):
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`.
pattern (:obj:`str` | `Pattern`, optional): Regex pattern. If not :obj:`None`, ``re.match``
is used on :attr:`telegram.ChosenInlineResult.result_id` to determine if an update
should be handled by this handler. This is accessible in the callback as
:attr:`telegram.ext.CallbackContext.matches`.
.. versionadded:: 13.6
Attributes:
callback (:obj:`callable`): The callback function for this handler.
@ -82,9 +92,37 @@ class ChosenInlineResultHandler(Handler[Update]):
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
the callback function.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
pattern (`Pattern`): Optional. Regex pattern to test
:attr:`telegram.ChosenInlineResult.result_id` against.
.. versionadded:: 13.6
"""
def __init__(
self,
callback: Callable[[Update, 'CallbackContext'], RT],
pass_update_queue: bool = False,
pass_job_queue: bool = False,
pass_user_data: bool = False,
pass_chat_data: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
pattern: Union[str, Pattern] = None,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
run_async=run_async,
)
if isinstance(pattern, str):
pattern = re.compile(pattern)
self.pattern = pattern
def check_update(self, update: object) -> Optional[Union[bool, object]]:
"""Determines whether an update should be passed to this handlers :attr:`callback`.
@ -95,4 +133,24 @@ class ChosenInlineResultHandler(Handler[Update]):
:obj:`bool`
"""
return isinstance(update, Update) and update.chosen_inline_result
if isinstance(update, Update) and update.chosen_inline_result:
if self.pattern:
match = re.match(self.pattern, update.chosen_inline_result.result_id)
if match:
return match
else:
return True
return None
def collect_additional_context(
self,
context: 'CallbackContext',
update: Update,
dispatcher: 'Dispatcher',
check_result: Union[bool, Match],
) -> None:
"""This function adds the matched regex pattern result to
:attr:`telegram.ext.CallbackContext.matches`."""
if self.pattern:
check_result = cast(Match, check_result)
context.matches = [check_result]

View file

@ -111,6 +111,12 @@ class TestChosenInlineResultHandler:
and isinstance(update.chosen_inline_result, ChosenInlineResult)
)
def callback_context_pattern(self, update, context):
if context.matches[0].groups():
self.test_flag = context.matches[0].groups() == ('res', '_id')
if context.matches[0].groupdict():
self.test_flag = context.matches[0].groupdict() == {'begin': 'res', 'end': '_id'}
def test_basic(self, dp, chosen_inline_result):
handler = ChosenInlineResultHandler(self.callback_basic)
dp.add_handler(handler)
@ -179,3 +185,27 @@ class TestChosenInlineResultHandler:
cdp.process_update(chosen_inline_result)
assert self.test_flag
def test_with_pattern(self, chosen_inline_result):
handler = ChosenInlineResultHandler(self.callback_basic, pattern='.*ult.*')
assert handler.check_update(chosen_inline_result)
chosen_inline_result.chosen_inline_result.result_id = 'nothing here'
assert not handler.check_update(chosen_inline_result)
chosen_inline_result.chosen_inline_result.result_id = 'result_id'
def test_context_pattern(self, cdp, chosen_inline_result):
handler = ChosenInlineResultHandler(
self.callback_context_pattern, pattern=r'(?P<begin>.*)ult(?P<end>.*)'
)
cdp.add_handler(handler)
cdp.process_update(chosen_inline_result)
assert self.test_flag
cdp.remove_handler(handler)
handler = ChosenInlineResultHandler(self.callback_context_pattern, pattern=r'(res)ult(.*)')
cdp.add_handler(handler)
cdp.process_update(chosen_inline_result)
assert self.test_flag