Drop Non-CallbackContext API (#2617)

This commit is contained in:
Poolitzer 2021-08-29 18:15:04 +02:00 committed by Hinrich Mahler
parent 4d493aff16
commit 641f931f19
47 changed files with 398 additions and 2971 deletions

View file

@ -1,8 +0,0 @@
:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/ext/regexhandler.py
telegram.ext.RegexHandler
=========================
.. autoclass:: telegram.ext.RegexHandler
:members:
:show-inheritance:

View file

@ -34,7 +34,6 @@ Handlers
telegram.ext.pollhandler telegram.ext.pollhandler
telegram.ext.precheckoutqueryhandler telegram.ext.precheckoutqueryhandler
telegram.ext.prefixhandler telegram.ext.prefixhandler
telegram.ext.regexhandler
telegram.ext.shippingqueryhandler telegram.ext.shippingqueryhandler
telegram.ext.stringcommandhandler telegram.ext.stringcommandhandler
telegram.ext.stringregexhandler telegram.ext.stringregexhandler

View file

@ -35,7 +35,6 @@ from .inlinequeryhandler import InlineQueryHandler
from .filters import BaseFilter, MessageFilter, UpdateFilter, Filters from .filters import BaseFilter, MessageFilter, UpdateFilter, Filters
from .messagehandler import MessageHandler from .messagehandler import MessageHandler
from .commandhandler import CommandHandler, PrefixHandler from .commandhandler import CommandHandler, PrefixHandler
from .regexhandler import RegexHandler
from .stringcommandhandler import StringCommandHandler from .stringcommandhandler import StringCommandHandler
from .stringregexhandler import StringRegexHandler from .stringregexhandler import StringRegexHandler
from .typehandler import TypeHandler from .typehandler import TypeHandler
@ -84,7 +83,6 @@ __all__ = (
'PollHandler', 'PollHandler',
'PreCheckoutQueryHandler', 'PreCheckoutQueryHandler',
'PrefixHandler', 'PrefixHandler',
'RegexHandler',
'ShippingQueryHandler', 'ShippingQueryHandler',
'StringCommandHandler', 'StringCommandHandler',
'StringRegexHandler', 'StringRegexHandler',

View file

@ -108,10 +108,6 @@ class CallbackContext(Generic[UD, CD, BD]):
Args: Args:
dispatcher (:class:`telegram.ext.Dispatcher`): dispatcher (:class:`telegram.ext.Dispatcher`):
""" """
if not dispatcher.use_context:
raise ValueError(
'CallbackContext should not be used with a non context aware ' 'dispatcher!'
)
self._dispatcher = dispatcher self._dispatcher = dispatcher
self._chat_id_and_data: Optional[Tuple[int, CD]] = None self._chat_id_and_data: Optional[Tuple[int, CD]] = None
self._user_id_and_data: Optional[Tuple[int, UD]] = None self._user_id_and_data: Optional[Tuple[int, UD]] = None

View file

@ -22,7 +22,6 @@ import re
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Callable, Callable,
Dict,
Match, Match,
Optional, Optional,
Pattern, Pattern,
@ -49,13 +48,6 @@ class CallbackQueryHandler(Handler[Update, CCT]):
Read the documentation of the ``re`` module for more information. Read the documentation of the ``re`` module for more information.
Note: Note:
* :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same
user or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
* If your bot allows arbitrary objects as ``callback_data``, it may happen that the * If your bot allows arbitrary objects as ``callback_data``, it may happen that the
original ``callback_data`` for the incoming :class:`telegram.CallbackQuery`` can not be original ``callback_data`` for the incoming :class:`telegram.CallbackQuery`` can not be
found. This is the case when either a malicious client tempered with the found. This is the case when either a malicious client tempered with the
@ -72,22 +64,10 @@ class CallbackQueryHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pattern (:obj:`str` | `Pattern` | :obj:`callable` | :obj:`type`, optional): pattern (:obj:`str` | `Pattern` | :obj:`callable` | :obj:`type`, optional):
Pattern to test :attr:`telegram.CallbackQuery.data` against. If a string or a regex Pattern to test :attr:`telegram.CallbackQuery.data` against. If a string or a regex
pattern is passed, :meth:`re.match` is used on :attr:`telegram.CallbackQuery.data` to pattern is passed, :meth:`re.match` is used on :attr:`telegram.CallbackQuery.data` to
@ -106,66 +86,30 @@ class CallbackQueryHandler(Handler[Update, CCT]):
.. versionchanged:: 13.6 .. versionchanged:: 13.6
Added support for arbitrary callback data. Added support for arbitrary callback data.
pass_groups (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groups()`` as a keyword argument called ``groups``.
Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``.
Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pattern (`Pattern` | :obj:`callable` | :obj:`type`): Optional. Regex pattern, callback or pattern (`Pattern` | :obj:`callable` | :obj:`type`): Optional. Regex pattern, callback or
type to test :attr:`telegram.CallbackQuery.data` against. type to test :attr:`telegram.CallbackQuery.data` against.
.. versionchanged:: 13.6 .. versionchanged:: 13.6
Added support for arbitrary callback data. Added support for arbitrary callback data.
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
callback function.
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
__slots__ = ('pattern', 'pass_groups', 'pass_groupdict') __slots__ = ('pattern',)
def __init__( def __init__(
self, self,
callback: Callable[[Update, CCT], RT], callback: Callable[[Update, CCT], RT],
pass_update_queue: bool = False,
pass_job_queue: bool = False,
pattern: Union[str, Pattern, type, Callable[[object], Optional[bool]]] = None, pattern: Union[str, Pattern, type, Callable[[object], Optional[bool]]] = None,
pass_groups: bool = False,
pass_groupdict: bool = False,
pass_user_data: bool = False,
pass_chat_data: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
super().__init__( super().__init__(
callback, 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, run_async=run_async,
) )
@ -173,8 +117,6 @@ class CallbackQueryHandler(Handler[Update, CCT]):
pattern = re.compile(pattern) pattern = re.compile(pattern)
self.pattern = pattern self.pattern = pattern
self.pass_groups = pass_groups
self.pass_groupdict = pass_groupdict
def check_update(self, update: object) -> Optional[Union[bool, object]]: def check_update(self, update: object) -> Optional[Union[bool, object]]:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """Determines whether an update should be passed to this handlers :attr:`callback`.
@ -202,25 +144,6 @@ class CallbackQueryHandler(Handler[Update, CCT]):
return True return True
return None return None
def collect_optional_args(
self,
dispatcher: 'Dispatcher',
update: Update = None,
check_result: Union[bool, Match] = None,
) -> Dict[str, object]:
"""Pass the results of ``re.match(pattern, data).{groups(), groupdict()}`` to the
callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if
needed.
"""
optional_args = super().collect_optional_args(dispatcher, update, check_result)
if self.pattern and not callable(self.pattern):
check_result = cast(Match, check_result)
if self.pass_groups:
optional_args['groups'] = check_result.groups()
if self.pass_groupdict:
optional_args['groupdict'] = check_result.groupdict()
return optional_args
def collect_additional_context( def collect_additional_context(
self, self,
context: CCT, context: CCT,

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class ChatJoinRequestHandler(Handler[Update, CCT]): class ChatJoinRequestHandler(Handler[Update, CCT]):
"""Handler class to handle Telegram updates that contain a chat join request. """Handler class to handle Telegram updates that contain a chat join request.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -52,35 +43,11 @@ class ChatJoinRequestHandler(Handler[Update, CCT]):
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """

View file

@ -32,15 +32,6 @@ class ChatMemberHandler(Handler[Update, CCT]):
.. versionadded:: 13.4 .. versionadded:: 13.4
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -48,9 +39,7 @@ class ChatMemberHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
@ -58,22 +47,6 @@ class ChatMemberHandler(Handler[Update, CCT]):
:attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle :attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle
only updates with :attr:`telegram.Update.my_chat_member`, only updates with :attr:`telegram.Update.my_chat_member`,
:attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`. :attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
@ -82,14 +55,6 @@ class ChatMemberHandler(Handler[Update, CCT]):
chat_member_types (:obj:`int`, optional): Specifies if this handler should handle chat_member_types (:obj:`int`, optional): Specifies if this handler should handle
only updates with :attr:`telegram.Update.my_chat_member`, only updates with :attr:`telegram.Update.my_chat_member`,
:attr:`telegram.Update.chat_member` or both. :attr:`telegram.Update.chat_member` or both.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
@ -107,18 +72,10 @@ class ChatMemberHandler(Handler[Update, CCT]):
self, self,
callback: Callable[[Update, CCT], RT], callback: Callable[[Update, CCT], RT],
chat_member_types: int = MY_CHAT_MEMBER, chat_member_types: int = MY_CHAT_MEMBER,
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, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
super().__init__( super().__init__(
callback, 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, run_async=run_async,
) )

View file

@ -35,15 +35,6 @@ if TYPE_CHECKING:
class ChosenInlineResultHandler(Handler[Update, CCT]): class ChosenInlineResultHandler(Handler[Update, CCT]):
"""Handler class to handle Telegram updates that contain a chosen inline result. """Handler class to handle Telegram updates that contain a chosen inline result.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -51,28 +42,10 @@ class ChosenInlineResultHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
pattern (:obj:`str` | `Pattern`, optional): Regex pattern. If not :obj:`None`, ``re.match`` pattern (:obj:`str` | `Pattern`, optional): Regex pattern. If not :obj:`None`, ``re.match``
@ -84,14 +57,6 @@ class ChosenInlineResultHandler(Handler[Update, CCT]):
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
pattern (`Pattern`): Optional. Regex pattern to test pattern (`Pattern`): Optional. Regex pattern to test
:attr:`telegram.ChosenInlineResult.result_id` against. :attr:`telegram.ChosenInlineResult.result_id` against.
@ -105,19 +70,11 @@ class ChosenInlineResultHandler(Handler[Update, CCT]):
def __init__( def __init__(
self, self,
callback: Callable[[Update, 'CallbackContext'], RT], 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, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
pattern: Union[str, Pattern] = None, pattern: Union[str, Pattern] = None,
): ):
super().__init__( super().__init__(
callback, 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, run_async=run_async,
) )

View file

@ -18,12 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the CommandHandler and PrefixHandler classes.""" """This module contains the CommandHandler and PrefixHandler classes."""
import re import re
import warnings
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple, TypeVar, Union from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple, TypeVar, Union
from telegram import MessageEntity, Update from telegram import MessageEntity, Update
from telegram.ext import BaseFilter, Filters from telegram.ext import BaseFilter, Filters
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.types import SLT from telegram.utils.types import SLT
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
@ -49,13 +47,6 @@ class CommandHandler(Handler[Update, CCT]):
Note: Note:
* :class:`CommandHandler` does *not* handle (edited) channel posts. * :class:`CommandHandler` does *not* handle (edited) channel posts.
* :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a :obj:`dict` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same
user or in the same chat, it will be the same :obj:`dict`.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
@ -67,9 +58,7 @@ class CommandHandler(Handler[Update, CCT]):
Limitations are the same as described here https://core.telegram.org/bots#commands Limitations are the same as described here https://core.telegram.org/bots#commands
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
@ -77,31 +66,6 @@ class CommandHandler(Handler[Update, CCT]):
:class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in
:class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise
operators (& for and, | for or, ~ for not). operators (& for and, | for or, ~ for not).
allow_edited (:obj:`bool`, optional): Determines whether the handler should also accept
edited messages. Default is :obj:`False`.
DEPRECATED: Edited is allowed by default. To change this behavior use
``~Filters.update.edited_message``.
pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the
arguments passed to the command as a keyword argument called ``args``. It will contain
a list of strings, which is the text following the command split on single or
consecutive whitespace characters. Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
@ -115,42 +79,20 @@ class CommandHandler(Handler[Update, CCT]):
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
Filters. Filters.
allow_edited (:obj:`bool`): Determines whether the handler should also accept
edited messages.
pass_args (:obj:`bool`): Determines whether the handler should be passed
``args``.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
__slots__ = ('command', 'filters', 'pass_args') __slots__ = ('command', 'filters')
def __init__( def __init__(
self, self,
command: SLT[str], command: SLT[str],
callback: Callable[[Update, CCT], RT], callback: Callable[[Update, CCT], RT],
filters: BaseFilter = None, filters: BaseFilter = None,
allow_edited: bool = None,
pass_args: bool = False,
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, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
super().__init__( super().__init__(
callback, 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, run_async=run_async,
) )
@ -167,16 +109,6 @@ class CommandHandler(Handler[Update, CCT]):
else: else:
self.filters = Filters.update.messages self.filters = Filters.update.messages
if allow_edited is not None:
warnings.warn(
'allow_edited is deprecated. See https://git.io/fxJuV for more info',
TelegramDeprecationWarning,
stacklevel=2,
)
if not allow_edited:
self.filters &= ~Filters.update.edited_message
self.pass_args = pass_args
def check_update( def check_update(
self, update: object self, update: object
) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]: ) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]:
@ -216,20 +148,6 @@ class CommandHandler(Handler[Update, CCT]):
return False return False
return None return None
def collect_optional_args(
self,
dispatcher: 'Dispatcher',
update: Update = None,
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]] = None,
) -> Dict[str, object]:
"""Provide text after the command to the callback the ``args`` argument as list, split on
single whitespaces.
"""
optional_args = super().collect_optional_args(dispatcher, update)
if self.pass_args and isinstance(check_result, tuple):
optional_args['args'] = check_result[0]
return optional_args
def collect_additional_context( def collect_additional_context(
self, self,
context: CCT, context: CCT,
@ -282,13 +200,6 @@ class PrefixHandler(CommandHandler):
Note: Note:
* :class:`PrefixHandler` does *not* handle (edited) channel posts. * :class:`PrefixHandler` does *not* handle (edited) channel posts.
* :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a :obj:`dict` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same
user or in the same chat, it will be the same :obj:`dict`.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
@ -301,9 +212,7 @@ class PrefixHandler(CommandHandler):
The command or list of commands this handler should listen for. The command or list of commands this handler should listen for.
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
@ -311,27 +220,6 @@ class PrefixHandler(CommandHandler):
:class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in
:class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise
operators (& for and, | for or, ~ for not). operators (& for and, | for or, ~ for not).
pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the
arguments passed to the command as a keyword argument called ``args``. It will contain
a list of strings, which is the text following the command split on single or
consecutive whitespace characters. Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
@ -339,16 +227,6 @@ class PrefixHandler(CommandHandler):
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
Filters. Filters.
pass_args (:obj:`bool`): Determines whether the handler should be passed
``args``.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
@ -362,11 +240,6 @@ class PrefixHandler(CommandHandler):
command: SLT[str], command: SLT[str],
callback: Callable[[Update, CCT], RT], callback: Callable[[Update, CCT], RT],
filters: BaseFilter = None, filters: BaseFilter = None,
pass_args: bool = False,
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, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
@ -378,12 +251,6 @@ class PrefixHandler(CommandHandler):
'nocommand', 'nocommand',
callback, callback,
filters=filters, filters=filters,
allow_edited=None,
pass_args=pass_args,
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, run_async=run_async,
) )

View file

@ -53,7 +53,7 @@ class _ConversationTimeoutContext:
conversation_key: Tuple[int, ...], conversation_key: Tuple[int, ...],
update: Update, update: Update,
dispatcher: 'Dispatcher', dispatcher: 'Dispatcher',
callback_context: Optional[CallbackContext], callback_context: CallbackContext,
): ):
self.conversation_key = conversation_key self.conversation_key = conversation_key
self.update = update self.update = update
@ -486,7 +486,7 @@ class ConversationHandler(Handler[Update, CCT]):
new_state: object, new_state: object,
dispatcher: 'Dispatcher', dispatcher: 'Dispatcher',
update: Update, update: Update,
context: Optional[CallbackContext], context: CallbackContext,
conversation_key: Tuple[int, ...], conversation_key: Tuple[int, ...],
) -> None: ) -> None:
if new_state != self.END: if new_state != self.END:
@ -598,7 +598,7 @@ class ConversationHandler(Handler[Update, CCT]):
update: Update, update: Update,
dispatcher: 'Dispatcher', dispatcher: 'Dispatcher',
check_result: CheckUpdateType, check_result: CheckUpdateType,
context: CallbackContext = None, context: CallbackContext,
) -> Optional[object]: ) -> Optional[object]:
"""Send the update to the callback for the current state and Handler """Send the update to the callback for the current state and Handler
@ -607,11 +607,10 @@ class ConversationHandler(Handler[Update, CCT]):
handler, and the handler's check result. handler, and the handler's check result.
update (:class:`telegram.Update`): Incoming telegram update. update (:class:`telegram.Update`): Incoming telegram update.
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update. dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by context (:class:`telegram.ext.CallbackContext`): The context as provided by
the dispatcher. the dispatcher.
""" """
update = cast(Update, update) # for mypy
conversation_key, handler, check_result = check_result # type: ignore[assignment,misc] conversation_key, handler, check_result = check_result # type: ignore[assignment,misc]
raise_dp_handler_stop = False raise_dp_handler_stop = False
@ -690,14 +689,10 @@ class ConversationHandler(Handler[Update, CCT]):
if self.persistent and self.persistence and self.name: if self.persistent and self.persistence and self.name:
self.persistence.update_conversation(self.name, key, new_state) self.persistence.update_conversation(self.name, key, new_state)
def _trigger_timeout(self, context: CallbackContext, job: 'Job' = None) -> None: def _trigger_timeout(self, context: CallbackContext) -> None:
self.logger.debug('conversation timeout was triggered!') self.logger.debug('conversation timeout was triggered!')
# Backward compatibility with bots that do not use CallbackContext job = cast('Job', context.job)
if isinstance(context, CallbackContext):
job = context.job
ctxt = cast(_ConversationTimeoutContext, job.context) # type: ignore[union-attr]
else:
ctxt = cast(_ConversationTimeoutContext, job.context) ctxt = cast(_ConversationTimeoutContext, job.context)
callback_context = ctxt.callback_context callback_context = ctxt.callback_context

View file

@ -135,9 +135,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
``@run_async`` decorator and :meth:`run_async`. Defaults to 4. ``@run_async`` decorator and :meth:`run_async`. Defaults to 4.
persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to
store data that should be persistent over restarts. store data that should be persistent over restarts.
use_context (:obj:`bool`, optional): If set to :obj:`True` uses the context based callback
API (ignored if `dispatcher` argument is used). Defaults to :obj:`True`.
**New users**: set this to :obj:`True`.
context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance
of :class:`telegram.ext.ContextTypes` to customize the types used in the of :class:`telegram.ext.ContextTypes` to customize the types used in the
``context`` interface. If not passed, the defaults documented in ``context`` interface. If not passed, the defaults documented in
@ -168,7 +165,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
__slots__ = ( __slots__ = (
'workers', 'workers',
'persistence', 'persistence',
'use_context',
'update_queue', 'update_queue',
'job_queue', 'job_queue',
'user_data', 'user_data',
@ -203,7 +199,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
exception_event: Event = None, exception_event: Event = None,
job_queue: 'JobQueue' = None, job_queue: 'JobQueue' = None,
persistence: BasePersistence = None, persistence: BasePersistence = None,
use_context: bool = True,
): ):
... ...
@ -216,7 +211,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
exception_event: Event = None, exception_event: Event = None,
job_queue: 'JobQueue' = None, job_queue: 'JobQueue' = None,
persistence: BasePersistence = None, persistence: BasePersistence = None,
use_context: bool = True,
context_types: ContextTypes[CCT, UD, CD, BD] = None, context_types: ContextTypes[CCT, UD, CD, BD] = None,
): ):
... ...
@ -229,23 +223,14 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
exception_event: Event = None, exception_event: Event = None,
job_queue: 'JobQueue' = None, job_queue: 'JobQueue' = None,
persistence: BasePersistence = None, persistence: BasePersistence = None,
use_context: bool = True,
context_types: ContextTypes[CCT, UD, CD, BD] = None, context_types: ContextTypes[CCT, UD, CD, BD] = None,
): ):
self.bot = bot self.bot = bot
self.update_queue = update_queue self.update_queue = update_queue
self.job_queue = job_queue self.job_queue = job_queue
self.workers = workers self.workers = workers
self.use_context = use_context
self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes()) self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes())
if not use_context:
warnings.warn(
'Old Handler API is deprecated - see https://git.io/fxJuV for details',
TelegramDeprecationWarning,
stacklevel=3,
)
if self.workers < 1: if self.workers < 1:
warnings.warn( warnings.warn(
'Asynchronous callbacks can not be processed without at least one worker thread.' 'Asynchronous callbacks can not be processed without at least one worker thread.'
@ -536,7 +521,7 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
for handler in self.handlers[group]: for handler in self.handlers[group]:
check = handler.check_update(update) check = handler.check_update(update)
if check is not None and check is not False: if check is not None and check is not False:
if not context and self.use_context: if not context:
context = self.context_types.context.from_update(update, self) context = self.context_types.context.from_update(update, self)
context.refresh_data() context.refresh_data()
handled = True handled = True
@ -743,16 +728,12 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
Args: Args:
callback (:obj:`callable`): The callback function for this error handler. Will be callback (:obj:`callable`): The callback function for this error handler. Will be
called when an error is raised. Callback signature for context based API: called when an error is raised.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: object, context: CallbackContext)``
The error that happened will be present in context.error. The error that happened will be present in context.error.
run_async (:obj:`bool`, optional): Whether this handlers callback should be run run_async (:obj:`bool`, optional): Whether this handlers callback should be run
asynchronously using :meth:`run_async`. Defaults to :obj:`False`. asynchronously using :meth:`run_async`. Defaults to :obj:`False`.
Note:
See https://git.io/fxJuV for more info about switching to context based API.
""" """
if callback in self.error_handlers: if callback in self.error_handlers:
self.logger.debug('The callback is already registered as an error handler. Ignoring.') self.logger.debug('The callback is already registered as an error handler. Ignoring.')
@ -789,7 +770,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
if self.error_handlers: if self.error_handlers:
for callback, run_async in self.error_handlers.items(): # pylint: disable=W0621 for callback, run_async in self.error_handlers.items(): # pylint: disable=W0621
if self.use_context:
context = self.context_types.context.from_error( context = self.context_types.context.from_error(
update, error, self, async_args=async_args, async_kwargs=async_kwargs update, error, self, async_args=async_args, async_kwargs=async_kwargs
) )
@ -797,11 +777,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
self.run_async(callback, update, context, update=update) self.run_async(callback, update, context, update=update)
else: else:
callback(update, context) callback(update, context)
else:
if run_async:
self.run_async(callback, self.bot, update, error, update=update)
else:
callback(self.bot, update, error)
else: else:
self.logger.exception( self.logger.exception(

View file

@ -18,9 +18,8 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the base class for handlers as used by the Dispatcher.""" """This module contains the base class for handlers as used by the Dispatcher."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union, Generic from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, Generic
from telegram import Update
from telegram.ext.utils.promise import Promise from telegram.ext.utils.promise import Promise
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
from telegram.ext.utils.types import CCT from telegram.ext.utils.types import CCT
@ -35,15 +34,6 @@ UT = TypeVar('UT')
class Handler(Generic[UT, CCT], ABC): class Handler(Generic[UT, CCT], ABC):
"""The base class for all update handlers. Create custom handlers by inheriting from it. """The base class for all update handlers. Create custom handlers by inheriting from it.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -51,68 +41,30 @@ class Handler(Generic[UT, CCT], ABC):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
__slots__ = ( __slots__ = (
'callback', 'callback',
'pass_update_queue',
'pass_job_queue',
'pass_user_data',
'pass_chat_data',
'run_async', 'run_async',
) )
def __init__( def __init__(
self, self,
callback: Callable[[UT, CCT], RT], callback: Callable[[UT, CCT], 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, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
self.callback = callback self.callback = callback
self.pass_update_queue = pass_update_queue
self.pass_job_queue = pass_job_queue
self.pass_user_data = pass_user_data
self.pass_chat_data = pass_chat_data
self.run_async = run_async self.run_async = run_async
@abstractmethod @abstractmethod
@ -140,7 +92,7 @@ class Handler(Generic[UT, CCT], ABC):
update: UT, update: UT,
dispatcher: 'Dispatcher', dispatcher: 'Dispatcher',
check_result: object, check_result: object,
context: CCT = None, context: CCT,
) -> Union[RT, Promise]: ) -> Union[RT, Promise]:
""" """
This method is called if it was determined that an update should indeed This method is called if it was determined that an update should indeed
@ -153,7 +105,7 @@ class Handler(Generic[UT, CCT], ABC):
update (:obj:`str` | :class:`telegram.Update`): The update to be handled. update (:obj:`str` | :class:`telegram.Update`): The update to be handled.
dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher. dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher.
check_result (:obj:`obj`): The result from :attr:`check_update`. check_result (:obj:`obj`): The result from :attr:`check_update`.
context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by context (:class:`telegram.ext.CallbackContext`): The context as provided by
the dispatcher. the dispatcher.
""" """
@ -165,19 +117,11 @@ class Handler(Generic[UT, CCT], ABC):
): ):
run_async = True run_async = True
if context:
self.collect_additional_context(context, update, dispatcher, check_result) self.collect_additional_context(context, update, dispatcher, check_result)
if run_async: if run_async:
return dispatcher.run_async(self.callback, update, context, update=update) return dispatcher.run_async(self.callback, update, context, update=update)
return self.callback(update, context) return self.callback(update, context)
optional_args = self.collect_optional_args(dispatcher, update, check_result)
if run_async:
return dispatcher.run_async(
self.callback, dispatcher.bot, update, update=update, **optional_args
)
return self.callback(dispatcher.bot, update, **optional_args) # type: ignore
def collect_additional_context( def collect_additional_context(
self, self,
context: CCT, context: CCT,
@ -194,41 +138,3 @@ class Handler(Generic[UT, CCT], ABC):
check_result: The result (return value) from :attr:`check_update`. check_result: The result (return value) from :attr:`check_update`.
""" """
def collect_optional_args(
self,
dispatcher: 'Dispatcher',
update: UT = None,
check_result: Any = None, # pylint: disable=W0613
) -> Dict[str, object]:
"""
Prepares the optional arguments. If the handler has additional optional args,
it should subclass this method, but remember to call this super method.
DEPRECATED: This method is being replaced by new context based callbacks. Please see
https://git.io/fxJuV for more info.
Args:
dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher.
update (:class:`telegram.Update`): The update to gather chat/user id from.
check_result: The result from check_update
"""
optional_args: Dict[str, object] = {}
if self.pass_update_queue:
optional_args['update_queue'] = dispatcher.update_queue
if self.pass_job_queue:
optional_args['job_queue'] = dispatcher.job_queue
if self.pass_user_data and isinstance(update, Update):
user = update.effective_user
optional_args['user_data'] = dispatcher.user_data[
user.id if user else None # type: ignore[index]
]
if self.pass_chat_data and isinstance(update, Update):
chat = update.effective_chat
optional_args['chat_data'] = dispatcher.chat_data[
chat.id if chat else None # type: ignore[index]
]
return optional_args

View file

@ -21,7 +21,6 @@ import re
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Callable, Callable,
Dict,
Match, Match,
Optional, Optional,
Pattern, Pattern,
@ -48,15 +47,6 @@ class InlineQueryHandler(Handler[Update, CCT]):
Handler class to handle Telegram inline queries. Optionally based on a regex. Read the Handler class to handle Telegram inline queries. Optionally based on a regex. Read the
documentation of the ``re`` module for more information. documentation of the ``re`` module for more information.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
* When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom * When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -67,22 +57,10 @@ class InlineQueryHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pattern (:obj:`str` | :obj:`Pattern`, optional): Regex pattern. If not :obj:`None`, pattern (:obj:`str` | :obj:`Pattern`, optional): Regex pattern. If not :obj:`None`,
``re.match`` is used on :attr:`telegram.InlineQuery.query` to determine if an update ``re.match`` is used on :attr:`telegram.InlineQuery.query` to determine if an update
should be handled by this handler. should be handled by this handler.
@ -90,67 +68,31 @@ class InlineQueryHandler(Handler[Update, CCT]):
handle inline queries with the appropriate :attr:`telegram.InlineQuery.chat_type`. handle inline queries with the appropriate :attr:`telegram.InlineQuery.chat_type`.
.. versionadded:: 13.5 .. versionadded:: 13.5
pass_groups (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groups()`` as a keyword argument called ``groups``.
Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``.
Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test
:attr:`telegram.InlineQuery.query` against. :attr:`telegram.InlineQuery.query` against.
chat_types (List[:obj:`str`], optional): List of allowed chat types. chat_types (List[:obj:`str`], optional): List of allowed chat types.
.. versionadded:: 13.5 .. versionadded:: 13.5
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
callback function.
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
__slots__ = ('pattern', 'chat_types', 'pass_groups', 'pass_groupdict') __slots__ = ('pattern', 'chat_types')
def __init__( def __init__(
self, self,
callback: Callable[[Update, CCT], RT], callback: Callable[[Update, CCT], RT],
pass_update_queue: bool = False,
pass_job_queue: bool = False,
pattern: Union[str, Pattern] = None, pattern: Union[str, Pattern] = None,
pass_groups: bool = False,
pass_groupdict: bool = False,
pass_user_data: bool = False,
pass_chat_data: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
chat_types: List[str] = None, chat_types: List[str] = None,
): ):
super().__init__( super().__init__(
callback, 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, run_async=run_async,
) )
@ -159,8 +101,6 @@ class InlineQueryHandler(Handler[Update, CCT]):
self.pattern = pattern self.pattern = pattern
self.chat_types = chat_types self.chat_types = chat_types
self.pass_groups = pass_groups
self.pass_groupdict = pass_groupdict
def check_update(self, update: object) -> Optional[Union[bool, Match]]: def check_update(self, update: object) -> Optional[Union[bool, Match]]:
""" """
@ -187,25 +127,6 @@ class InlineQueryHandler(Handler[Update, CCT]):
return True return True
return None return None
def collect_optional_args(
self,
dispatcher: 'Dispatcher',
update: Update = None,
check_result: Optional[Union[bool, Match]] = None,
) -> Dict[str, object]:
"""Pass the results of ``re.match(pattern, query).{groups(), groupdict()}`` to the
callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if
needed.
"""
optional_args = super().collect_optional_args(dispatcher, update, check_result)
if self.pattern:
check_result = cast(Match, check_result)
if self.pass_groups:
optional_args['groups'] = check_result.groups()
if self.pass_groupdict:
optional_args['groupdict'] = check_result.groupdict()
return optional_args
def collect_additional_context( def collect_additional_context(
self, self,
context: CCT, context: CCT,

View file

@ -31,7 +31,6 @@ from telegram.ext.callbackcontext import CallbackContext
from telegram.utils.types import JSONDict from telegram.utils.types import JSONDict
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot
from telegram.ext import Dispatcher from telegram.ext import Dispatcher
import apscheduler.job # noqa: F401 import apscheduler.job # noqa: F401
@ -64,10 +63,8 @@ class JobQueue:
logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter) logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter)
self.scheduler.add_listener(self._dispatch_error, EVENT_JOB_ERROR) self.scheduler.add_listener(self._dispatch_error, EVENT_JOB_ERROR)
def _build_args(self, job: 'Job') -> List[Union[CallbackContext, 'Bot', 'Job']]: def _build_args(self, job: 'Job') -> List[CallbackContext]:
if self._dispatcher.use_context:
return [self._dispatcher.context_types.context.from_job(job, self._dispatcher)] return [self._dispatcher.context_types.context.from_job(job, self._dispatcher)]
return [self._dispatcher.bot, job]
def _tz_now(self) -> datetime.datetime: def _tz_now(self) -> datetime.datetime:
return datetime.datetime.now(self.scheduler.timezone) return datetime.datetime.now(self.scheduler.timezone)
@ -145,12 +142,7 @@ class JobQueue:
Args: Args:
callback (:obj:`callable`): The callback function that should be executed by the new callback (:obj:`callable`): The callback function that should be executed by the new
job. Callback signature for context based API: job. Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \
:obj:`datetime.datetime` | :obj:`datetime.time`): :obj:`datetime.datetime` | :obj:`datetime.time`):
Time in or at which the job should run. This parameter will be interpreted Time in or at which the job should run. This parameter will be interpreted
@ -220,12 +212,7 @@ class JobQueue:
Args: Args:
callback (:obj:`callable`): The callback function that should be executed by the new callback (:obj:`callable`): The callback function that should be executed by the new
job. Callback signature for context based API: job. Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which
the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted
as seconds. as seconds.
@ -315,12 +302,7 @@ class JobQueue:
Args: Args:
callback (:obj:`callable`): The callback function that should be executed by the new callback (:obj:`callable`): The callback function that should be executed by the new
job. Callback signature for context based API: job. Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
when (:obj:`datetime.time`): Time of day at which the job should run. If the timezone when (:obj:`datetime.time`): Time of day at which the job should run. If the timezone
(``when.tzinfo``) is :obj:`None`, the default timezone of the bot will be used. (``when.tzinfo``) is :obj:`None`, the default timezone of the bot will be used.
day (:obj:`int`): Defines the day of the month whereby the job would run. It should day (:obj:`int`): Defines the day of the month whereby the job would run. It should
@ -379,12 +361,7 @@ class JobQueue:
Args: Args:
callback (:obj:`callable`): The callback function that should be executed by the new callback (:obj:`callable`): The callback function that should be executed by the new
job. Callback signature for context based API: job. Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone
(``time.tzinfo``) is :obj:`None`, the default timezone of the bot will be used. (``time.tzinfo``) is :obj:`None`, the default timezone of the bot will be used.
days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should
@ -434,12 +411,7 @@ class JobQueue:
Args: Args:
callback (:obj:`callable`): The callback function that should be executed by the new callback (:obj:`callable`): The callback function that should be executed by the new
job. Callback signature for context based API: job. Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(CallbackContext)``
``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for
``scheduler.add_job``. ``scheduler.add_job``.
context (:obj:`object`, optional): Additional data needed for the callback function. context (:obj:`object`, optional): Additional data needed for the callback function.
@ -502,12 +474,7 @@ class Job:
Args: Args:
callback (:obj:`callable`): The callback function that should be executed by the new job. callback (:obj:`callable`): The callback function that should be executed by the new job.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(CallbackContext)``
a ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access
its ``job.context`` or change it to a repeating job.
context (:obj:`object`, optional): Additional data needed for the callback function. Can be context (:obj:`object`, optional): Additional data needed for the callback function. Can be
accessed through ``job.context`` in the callback. Defaults to :obj:`None`. accessed through ``job.context`` in the callback. Defaults to :obj:`None`.
name (:obj:`str`, optional): The name of the new job. Defaults to ``callback.__name__``. name (:obj:`str`, optional): The name of the new job. Defaults to ``callback.__name__``.
@ -555,10 +522,7 @@ class Job:
def run(self, dispatcher: 'Dispatcher') -> None: def run(self, dispatcher: 'Dispatcher') -> None:
"""Executes the callback function independently of the jobs schedule.""" """Executes the callback function independently of the jobs schedule."""
try: try:
if dispatcher.use_context:
self.callback(dispatcher.context_types.context.from_job(self, dispatcher)) self.callback(dispatcher.context_types.context.from_job(self, dispatcher))
else:
self.callback(dispatcher.bot, self) # type: ignore[arg-type,call-arg]
except Exception as exc: except Exception as exc:
try: try:
dispatcher.dispatch_error(None, exc) dispatcher.dispatch_error(None, exc)

View file

@ -16,14 +16,11 @@
# #
# You should have received a copy of the GNU Lesser Public License # You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
# TODO: Remove allow_edited
"""This module contains the MessageHandler class.""" """This module contains the MessageHandler class."""
import warnings
from typing import TYPE_CHECKING, Callable, Dict, Optional, TypeVar, Union from typing import TYPE_CHECKING, Callable, Dict, Optional, TypeVar, Union
from telegram import Update from telegram import Update
from telegram.ext import BaseFilter, Filters from telegram.ext import BaseFilter, Filters
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
from .handler import Handler from .handler import Handler
@ -38,15 +35,6 @@ RT = TypeVar('RT')
class MessageHandler(Handler[Update, CCT]): class MessageHandler(Handler[Update, CCT]):
"""Handler class to handle telegram messages. They might contain text, media or status updates. """Handler class to handle telegram messages. They might contain text, media or status updates.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -62,37 +50,10 @@ class MessageHandler(Handler[Update, CCT]):
argument. argument.
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
message_updates (:obj:`bool`, optional): Should "normal" message updates be handled?
Default is :obj:`None`.
DEPRECATED: Please switch to filters for update filtering.
channel_post_updates (:obj:`bool`, optional): Should channel posts updates be handled?
Default is :obj:`None`.
DEPRECATED: Please switch to filters for update filtering.
edited_updates (:obj:`bool`, optional): Should "edited" message updates be handled? Default
is :obj:`None`.
DEPRECATED: Please switch to filters for update filtering.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
@ -103,20 +64,6 @@ class MessageHandler(Handler[Update, CCT]):
filters (:obj:`Filter`): Only allow updates with these Filters. See filters (:obj:`Filter`): Only allow updates with these Filters. See
:mod:`telegram.ext.filters` for a full list of all available filters. :mod:`telegram.ext.filters` for a full list of all available filters.
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
the callback function.
message_updates (:obj:`bool`): Should "normal" message updates be handled?
Default is :obj:`None`.
channel_post_updates (:obj:`bool`): Should channel posts updates be handled?
Default is :obj:`None`.
edited_updates (:obj:`bool`): Should "edited" message updates be handled?
Default is :obj:`None`.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
@ -127,60 +74,17 @@ class MessageHandler(Handler[Update, CCT]):
self, self,
filters: BaseFilter, filters: BaseFilter,
callback: Callable[[Update, CCT], RT], callback: Callable[[Update, CCT], RT],
pass_update_queue: bool = False,
pass_job_queue: bool = False,
pass_user_data: bool = False,
pass_chat_data: bool = False,
message_updates: bool = None,
channel_post_updates: bool = None,
edited_updates: bool = None,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
super().__init__( super().__init__(
callback, 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, run_async=run_async,
) )
if message_updates is False and channel_post_updates is False and edited_updates is False:
raise ValueError(
'message_updates, channel_post_updates and edited_updates are all False'
)
if filters is not None: if filters is not None:
self.filters = Filters.update & filters self.filters = Filters.update & filters
else: else:
self.filters = Filters.update self.filters = Filters.update
if message_updates is not None:
warnings.warn(
'message_updates is deprecated. See https://git.io/fxJuV for more info',
TelegramDeprecationWarning,
stacklevel=2,
)
if message_updates is False:
self.filters &= ~Filters.update.message
if channel_post_updates is not None:
warnings.warn(
'channel_post_updates is deprecated. See https://git.io/fxJuV ' 'for more info',
TelegramDeprecationWarning,
stacklevel=2,
)
if channel_post_updates is False:
self.filters &= ~Filters.update.channel_post
if edited_updates is not None:
warnings.warn(
'edited_updates is deprecated. See https://git.io/fxJuV for more info',
TelegramDeprecationWarning,
stacklevel=2,
)
if edited_updates is False:
self.filters &= ~(
Filters.update.edited_message | Filters.update.edited_channel_post
)
def check_update(self, update: object) -> Optional[Union[bool, Dict[str, list]]]: def check_update(self, update: object) -> Optional[Union[bool, Dict[str, list]]]:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """Determines whether an update should be passed to this handlers :attr:`callback`.
@ -192,7 +96,7 @@ class MessageHandler(Handler[Update, CCT]):
:obj:`bool` :obj:`bool`
""" """
if isinstance(update, Update) and update.effective_message: if isinstance(update, Update):
return self.filters(update) return self.filters(update)
return None return None

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class PollAnswerHandler(Handler[Update, CCT]): class PollAnswerHandler(Handler[Update, CCT]):
"""Handler class to handle Telegram updates that contain a poll answer. """Handler class to handle Telegram updates that contain a poll answer.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -44,41 +35,15 @@ class PollAnswerHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class PollHandler(Handler[Update, CCT]): class PollHandler(Handler[Update, CCT]):
"""Handler class to handle Telegram updates that contain a poll. """Handler class to handle Telegram updates that contain a poll.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -44,41 +35,15 @@ class PollHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class PreCheckoutQueryHandler(Handler[Update, CCT]): class PreCheckoutQueryHandler(Handler[Update, CCT]):
"""Handler class to handle Telegram PreCheckout callback queries. """Handler class to handle Telegram PreCheckout callback queries.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -44,41 +35,15 @@ class PreCheckoutQueryHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
DEPRECATED: Please switch to context based callbacks.
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """

View file

@ -1,166 +0,0 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
# TODO: Remove allow_edited
"""This module contains the RegexHandler class."""
import warnings
from typing import TYPE_CHECKING, Callable, Dict, Optional, Pattern, TypeVar, Union, Any
from telegram import Update
from telegram.ext import Filters, MessageHandler
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
from telegram.ext.utils.types import CCT
if TYPE_CHECKING:
from telegram.ext import Dispatcher
RT = TypeVar('RT')
class RegexHandler(MessageHandler):
"""Handler class to handle Telegram updates based on a regex.
It uses a regular expression to check text messages. Read the documentation of the ``re``
module for more information. The ``re.match`` function is used to determine if an update should
be handled by this handler.
Note:
This handler is being deprecated. For the same use case use:
``MessageHandler(Filters.regex(r'pattern'), callback)``
Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
Args:
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API:
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
pass_groups (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groups()`` as a keyword argument called ``groups``.
Default is :obj:`False`
pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``.
Default is :obj:`False`
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
message_updates (:obj:`bool`, optional): Should "normal" message updates be handled?
Default is :obj:`True`.
channel_post_updates (:obj:`bool`, optional): Should channel posts updates be handled?
Default is :obj:`True`.
edited_updates (:obj:`bool`, optional): Should "edited" message updates be handled? Default
is :obj:`False`.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`.
Raises:
ValueError
Attributes:
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
callback (:obj:`callable`): The callback function for this handler.
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
callback function.
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
the callback function.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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.
"""
__slots__ = ('pass_groups', 'pass_groupdict')
def __init__(
self,
pattern: Union[str, Pattern],
callback: Callable[[Update, CCT], RT],
pass_groups: bool = False,
pass_groupdict: bool = False,
pass_update_queue: bool = False,
pass_job_queue: bool = False,
pass_user_data: bool = False,
pass_chat_data: bool = False,
allow_edited: bool = False, # pylint: disable=W0613
message_updates: bool = True,
channel_post_updates: bool = False,
edited_updates: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
):
warnings.warn(
'RegexHandler is deprecated. See https://git.io/fxJuV for more info',
TelegramDeprecationWarning,
stacklevel=2,
)
super().__init__(
Filters.regex(pattern),
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,
message_updates=message_updates,
channel_post_updates=channel_post_updates,
edited_updates=edited_updates,
run_async=run_async,
)
self.pass_groups = pass_groups
self.pass_groupdict = pass_groupdict
def collect_optional_args(
self,
dispatcher: 'Dispatcher',
update: Update = None,
check_result: Optional[Union[bool, Dict[str, Any]]] = None,
) -> Dict[str, object]:
"""Pass the results of ``re.match(pattern, text).{groups(), groupdict()}`` to the
callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if
needed.
"""
optional_args = super().collect_optional_args(dispatcher, update, check_result)
if isinstance(check_result, dict):
if self.pass_groups:
optional_args['groups'] = check_result['matches'][0].groups()
if self.pass_groupdict:
optional_args['groupdict'] = check_result['matches'][0].groupdict()
return optional_args

View file

@ -27,15 +27,6 @@ from .utils.types import CCT
class ShippingQueryHandler(Handler[Update, CCT]): class ShippingQueryHandler(Handler[Update, CCT]):
"""Handler class to handle Telegram shipping callback queries. """Handler class to handle Telegram shipping callback queries.
Note:
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
can use to keep any data in will be sent to the :attr:`callback` function. Related to
either the user or the chat that the update was sent in. For each update from the same user
or in the same chat, it will be the same ``dict``.
Note that this is DEPRECATED, and you should use context based callbacks. See
https://git.io/fxJuV for more info.
Warning: Warning:
When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
@ -43,41 +34,15 @@ class ShippingQueryHandler(Handler[Update, CCT]):
Args: Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``user_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``chat_data`` will be passed to the callback function. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
the callback function.
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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """

View file

@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the StringCommandHandler class.""" """This module contains the StringCommandHandler class."""
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, TypeVar, Union from typing import TYPE_CHECKING, Callable, List, Optional, TypeVar, Union
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
@ -49,62 +49,33 @@ class StringCommandHandler(Handler[str, CCT]):
command (:obj:`str`): The command this handler should listen for. command (:obj:`str`): The command this handler should listen for.
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the
arguments passed to the command as a keyword argument called ``args``. It will contain
a list of strings, which is the text following the command split on single or
consecutive whitespace characters. Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
command (:obj:`str`): The command this handler should listen for. command (:obj:`str`): The command this handler should listen for.
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_args (:obj:`bool`): Determines whether the handler should be passed
``args``.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
__slots__ = ('command', 'pass_args') __slots__ = ('command',)
def __init__( def __init__(
self, self,
command: str, command: str,
callback: Callable[[str, CCT], RT], callback: Callable[[str, CCT], RT],
pass_args: bool = False,
pass_update_queue: bool = False,
pass_job_queue: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
super().__init__( super().__init__(
callback, callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
run_async=run_async, run_async=run_async,
) )
self.command = command self.command = command
self.pass_args = pass_args
def check_update(self, update: object) -> Optional[List[str]]: def check_update(self, update: object) -> Optional[List[str]]:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """Determines whether an update should be passed to this handlers :attr:`callback`.
@ -122,20 +93,6 @@ class StringCommandHandler(Handler[str, CCT]):
return args[1:] return args[1:]
return None return None
def collect_optional_args(
self,
dispatcher: 'Dispatcher',
update: str = None,
check_result: Optional[List[str]] = None,
) -> Dict[str, object]:
"""Provide text after the command to the callback the ``args`` argument as list, split on
single whitespaces.
"""
optional_args = super().collect_optional_args(dispatcher, update, check_result)
if self.pass_args:
optional_args['args'] = check_result
return optional_args
def collect_additional_context( def collect_additional_context(
self, self,
context: CCT, context: CCT,

View file

@ -19,7 +19,7 @@
"""This module contains the StringRegexHandler class.""" """This module contains the StringRegexHandler class."""
import re import re
from typing import TYPE_CHECKING, Callable, Dict, Match, Optional, Pattern, TypeVar, Union from typing import TYPE_CHECKING, Callable, Match, Optional, Pattern, TypeVar, Union
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
@ -50,64 +50,30 @@ class StringRegexHandler(Handler[str, CCT]):
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
pass_groups (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groups()`` as a keyword argument called ``groups``.
Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of
``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``.
Default is :obj:`False`
DEPRECATED: Please switch to context based callbacks.
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
Attributes: Attributes:
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the
callback function.
pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to
the callback function.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
__slots__ = ('pass_groups', 'pass_groupdict', 'pattern') __slots__ = ('pattern',)
def __init__( def __init__(
self, self,
pattern: Union[str, Pattern], pattern: Union[str, Pattern],
callback: Callable[[str, CCT], RT], callback: Callable[[str, CCT], RT],
pass_groups: bool = False,
pass_groupdict: bool = False,
pass_update_queue: bool = False,
pass_job_queue: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
super().__init__( super().__init__(
callback, callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
run_async=run_async, run_async=run_async,
) )
@ -115,8 +81,6 @@ class StringRegexHandler(Handler[str, CCT]):
pattern = re.compile(pattern) pattern = re.compile(pattern)
self.pattern = pattern self.pattern = pattern
self.pass_groups = pass_groups
self.pass_groupdict = pass_groupdict
def check_update(self, update: object) -> Optional[Match]: def check_update(self, update: object) -> Optional[Match]:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """Determines whether an update should be passed to this handlers :attr:`callback`.
@ -134,24 +98,6 @@ class StringRegexHandler(Handler[str, CCT]):
return match return match
return None return None
def collect_optional_args(
self,
dispatcher: 'Dispatcher',
update: str = None,
check_result: Optional[Match] = None,
) -> Dict[str, object]:
"""Pass the results of ``re.match(pattern, update).{groups(), groupdict()}`` to the
callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if
needed.
"""
optional_args = super().collect_optional_args(dispatcher, update, check_result)
if self.pattern:
if self.pass_groups and check_result:
optional_args['groups'] = check_result.groups()
if self.pass_groupdict and check_result:
optional_args['groupdict'] = check_result.groupdict()
return optional_args
def collect_additional_context( def collect_additional_context(
self, self,
context: CCT, context: CCT,

View file

@ -40,24 +40,12 @@ class TypeHandler(Handler[UT, CCT]):
determined by ``isinstance`` determined by ``isinstance``
callback (:obj:`callable`): The callback function for this handler. Will be called when callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler. :attr:`check_update` has determined that an update should be processed by this handler.
Callback signature for context based API: Callback signature: ``def callback(update: Update, context: CallbackContext)``
``def callback(update: Update, context: CallbackContext)``
The return value of the callback is usually ignored except for the special case of The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`. :class:`telegram.ext.ConversationHandler`.
strict (:obj:`bool`, optional): Use ``type`` instead of ``isinstance``. strict (:obj:`bool`, optional): Use ``type`` instead of ``isinstance``.
Default is :obj:`False` Default is :obj:`False`
pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``update_queue`` will be passed to the callback function. It will be the ``Queue``
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
that contains new updates which can be used to insert updates. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
``job_queue`` will be passed to the callback function. It will be a
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
which can be used to schedule new jobs. Default is :obj:`False`.
DEPRECATED: Please switch to context based callbacks.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
Defaults to :obj:`False`. Defaults to :obj:`False`.
@ -65,10 +53,6 @@ class TypeHandler(Handler[UT, CCT]):
type (:obj:`type`): The ``type`` of updates this handler should process. type (:obj:`type`): The ``type`` of updates this handler should process.
callback (:obj:`callable`): The callback function for this handler. callback (:obj:`callable`): The callback function for this handler.
strict (:obj:`bool`): Use ``type`` instead of ``isinstance``. Default is :obj:`False`. strict (:obj:`bool`): Use ``type`` instead of ``isinstance``. Default is :obj:`False`.
pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
passed to the callback function.
pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
the callback function.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
@ -80,14 +64,10 @@ class TypeHandler(Handler[UT, CCT]):
type: Type[UT], # pylint: disable=W0622 type: Type[UT], # pylint: disable=W0622
callback: Callable[[UT, CCT], RT], callback: Callable[[UT, CCT], RT],
strict: bool = False, strict: bool = False,
pass_update_queue: bool = False,
pass_job_queue: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
): ):
super().__init__( super().__init__(
callback, callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
run_async=run_async, run_async=run_async,
) )
self.type = type # pylint: disable=E0237 self.type = type # pylint: disable=E0237

View file

@ -93,9 +93,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
`telegram.utils.request.Request` object (ignored if `bot` or `dispatcher` argument is `telegram.utils.request.Request` object (ignored if `bot` or `dispatcher` argument is
used). The request_kwargs are very useful for the advanced users who would like to used). The request_kwargs are very useful for the advanced users who would like to
control the default timeouts and/or control the proxy used for http communication. control the default timeouts and/or control the proxy used for http communication.
use_context (:obj:`bool`, optional): If set to :obj:`True` uses the context based callback
API (ignored if `dispatcher` argument is used). Defaults to :obj:`True`.
**New users**: set this to :obj:`True`.
persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to
store data that should be persistent over restarts (ignored if `dispatcher` argument is store data that should be persistent over restarts (ignored if `dispatcher` argument is
used). used).
@ -129,7 +126,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
running (:obj:`bool`): Indicates if the updater is running. running (:obj:`bool`): Indicates if the updater is running.
persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to
store data that should be persistent over restarts. store data that should be persistent over restarts.
use_context (:obj:`bool`): Optional. :obj:`True` if using context based callbacks.
""" """
@ -164,7 +160,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
request_kwargs: Dict[str, Any] = None, request_kwargs: Dict[str, Any] = None,
persistence: 'BasePersistence' = None, # pylint: disable=E0601 persistence: 'BasePersistence' = None, # pylint: disable=E0601
defaults: 'Defaults' = None, defaults: 'Defaults' = None,
use_context: bool = True,
base_file_url: str = None, base_file_url: str = None,
arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE,
): ):
@ -183,7 +178,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
request_kwargs: Dict[str, Any] = None, request_kwargs: Dict[str, Any] = None,
persistence: 'BasePersistence' = None, persistence: 'BasePersistence' = None,
defaults: 'Defaults' = None, defaults: 'Defaults' = None,
use_context: bool = True,
base_file_url: str = None, base_file_url: str = None,
arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE,
context_types: ContextTypes[CCT, UD, CD, BD] = None, context_types: ContextTypes[CCT, UD, CD, BD] = None,
@ -210,7 +204,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
request_kwargs: Dict[str, Any] = None, request_kwargs: Dict[str, Any] = None,
persistence: 'BasePersistence' = None, persistence: 'BasePersistence' = None,
defaults: 'Defaults' = None, defaults: 'Defaults' = None,
use_context: bool = True,
dispatcher=None, dispatcher=None,
base_file_url: str = None, base_file_url: str = None,
arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE,
@ -243,8 +236,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
raise ValueError('`dispatcher` and `bot` are mutually exclusive') raise ValueError('`dispatcher` and `bot` are mutually exclusive')
if persistence is not None: if persistence is not None:
raise ValueError('`dispatcher` and `persistence` are mutually exclusive') raise ValueError('`dispatcher` and `persistence` are mutually exclusive')
if use_context != dispatcher.use_context:
raise ValueError('`dispatcher` and `use_context` are mutually exclusive')
if context_types is not None: if context_types is not None:
raise ValueError('`dispatcher` and `context_types` are mutually exclusive') raise ValueError('`dispatcher` and `context_types` are mutually exclusive')
if workers is not None: if workers is not None:
@ -300,7 +291,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
workers=workers, workers=workers,
exception_event=self.__exception_event, exception_event=self.__exception_event,
persistence=persistence, persistence=persistence,
use_context=use_context,
context_types=context_types, context_types=context_types,
) )
self.job_queue.set_dispatcher(self.dispatcher) self.job_queue.set_dispatcher(self.dispatcher)

View file

@ -159,7 +159,7 @@ def provider_token(bot_info):
def create_dp(bot): def create_dp(bot):
# Dispatcher is heavy to init (due to many threads and such) so we have a single session # Dispatcher is heavy to init (due to many threads and such) so we have a single session
# scoped one here, but before each test, reset it (dp fixture below) # scoped one here, but before each test, reset it (dp fixture below)
dispatcher = Dispatcher(bot, Queue(), job_queue=JobQueue(), workers=2, use_context=False) dispatcher = Dispatcher(bot, Queue(), job_queue=JobQueue(), workers=2)
dispatcher.job_queue.set_dispatcher(dispatcher) dispatcher.job_queue.set_dispatcher(dispatcher)
thr = Thread(target=dispatcher.start) thr = Thread(target=dispatcher.start)
thr.start() thr.start()
@ -195,23 +195,15 @@ def dp(_dp):
object.__setattr__(_dp, '__async_queue', Queue()) object.__setattr__(_dp, '__async_queue', Queue())
object.__setattr__(_dp, '__async_threads', set()) object.__setattr__(_dp, '__async_threads', set())
_dp.persistence = None _dp.persistence = None
_dp.use_context = False
if _dp._Dispatcher__singleton_semaphore.acquire(blocking=0): if _dp._Dispatcher__singleton_semaphore.acquire(blocking=0):
Dispatcher._set_singleton(_dp) Dispatcher._set_singleton(_dp)
yield _dp yield _dp
Dispatcher._Dispatcher__singleton_semaphore.release() Dispatcher._Dispatcher__singleton_semaphore.release()
@pytest.fixture(scope='function')
def cdp(dp):
dp.use_context = True
yield dp
dp.use_context = False
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def updater(bot): def updater(bot):
up = Updater(bot=bot, workers=2, use_context=False) up = Updater(bot=bot, workers=2)
yield up yield up
if up.running: if up.running:
up.stop() up.stop()

View file

@ -38,8 +38,8 @@ CallbackContext.refresh_data is tested in TestBasePersistence
class TestCallbackContext: class TestCallbackContext:
def test_slot_behaviour(self, cdp, mro_slots, recwarn): def test_slot_behaviour(self, dp, mro_slots, recwarn):
c = CallbackContext(cdp) c = CallbackContext(dp)
for attr in c.__slots__: for attr in c.__slots__:
assert getattr(c, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(c, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert not c.__dict__, f"got missing slot(s): {c.__dict__}" assert not c.__dict__, f"got missing slot(s): {c.__dict__}"
@ -47,38 +47,34 @@ class TestCallbackContext:
c.args = c.args c.args = c.args
assert len(recwarn) == 0, recwarn.list assert len(recwarn) == 0, recwarn.list
def test_non_context_dp(self, dp): def test_from_job(self, dp):
with pytest.raises(ValueError): job = dp.job_queue.run_once(lambda x: x, 10)
CallbackContext(dp)
def test_from_job(self, cdp): callback_context = CallbackContext.from_job(job, dp)
job = cdp.job_queue.run_once(lambda x: x, 10)
callback_context = CallbackContext.from_job(job, cdp)
assert callback_context.job is job assert callback_context.job is job
assert callback_context.chat_data is None assert callback_context.chat_data is None
assert callback_context.user_data is None assert callback_context.user_data is None
assert callback_context.bot_data is cdp.bot_data assert callback_context.bot_data is dp.bot_data
assert callback_context.bot is cdp.bot assert callback_context.bot is dp.bot
assert callback_context.job_queue is cdp.job_queue assert callback_context.job_queue is dp.job_queue
assert callback_context.update_queue is cdp.update_queue assert callback_context.update_queue is dp.update_queue
def test_from_update(self, cdp): def test_from_update(self, dp):
update = Update( update = Update(
0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False)) 0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False))
) )
callback_context = CallbackContext.from_update(update, cdp) callback_context = CallbackContext.from_update(update, dp)
assert callback_context.chat_data == {} assert callback_context.chat_data == {}
assert callback_context.user_data == {} assert callback_context.user_data == {}
assert callback_context.bot_data is cdp.bot_data assert callback_context.bot_data is dp.bot_data
assert callback_context.bot is cdp.bot assert callback_context.bot is dp.bot
assert callback_context.job_queue is cdp.job_queue assert callback_context.job_queue is dp.job_queue
assert callback_context.update_queue is cdp.update_queue assert callback_context.update_queue is dp.update_queue
callback_context_same_user_chat = CallbackContext.from_update(update, cdp) callback_context_same_user_chat = CallbackContext.from_update(update, dp)
callback_context.bot_data['test'] = 'bot' callback_context.bot_data['test'] = 'bot'
callback_context.chat_data['test'] = 'chat' callback_context.chat_data['test'] = 'chat'
@ -92,66 +88,66 @@ class TestCallbackContext:
0, message=Message(0, None, Chat(2, 'chat'), from_user=User(2, 'user', False)) 0, message=Message(0, None, Chat(2, 'chat'), from_user=User(2, 'user', False))
) )
callback_context_other_user_chat = CallbackContext.from_update(update_other_user_chat, cdp) callback_context_other_user_chat = CallbackContext.from_update(update_other_user_chat, dp)
assert callback_context_other_user_chat.bot_data is callback_context.bot_data assert callback_context_other_user_chat.bot_data is callback_context.bot_data
assert callback_context_other_user_chat.chat_data is not callback_context.chat_data assert callback_context_other_user_chat.chat_data is not callback_context.chat_data
assert callback_context_other_user_chat.user_data is not callback_context.user_data assert callback_context_other_user_chat.user_data is not callback_context.user_data
def test_from_update_not_update(self, cdp): def test_from_update_not_update(self, dp):
callback_context = CallbackContext.from_update(None, cdp) callback_context = CallbackContext.from_update(None, dp)
assert callback_context.chat_data is None assert callback_context.chat_data is None
assert callback_context.user_data is None assert callback_context.user_data is None
assert callback_context.bot_data is cdp.bot_data assert callback_context.bot_data is dp.bot_data
assert callback_context.bot is cdp.bot assert callback_context.bot is dp.bot
assert callback_context.job_queue is cdp.job_queue assert callback_context.job_queue is dp.job_queue
assert callback_context.update_queue is cdp.update_queue assert callback_context.update_queue is dp.update_queue
callback_context = CallbackContext.from_update('', cdp) callback_context = CallbackContext.from_update('', dp)
assert callback_context.chat_data is None assert callback_context.chat_data is None
assert callback_context.user_data is None assert callback_context.user_data is None
assert callback_context.bot_data is cdp.bot_data assert callback_context.bot_data is dp.bot_data
assert callback_context.bot is cdp.bot assert callback_context.bot is dp.bot
assert callback_context.job_queue is cdp.job_queue assert callback_context.job_queue is dp.job_queue
assert callback_context.update_queue is cdp.update_queue assert callback_context.update_queue is dp.update_queue
def test_from_error(self, cdp): def test_from_error(self, dp):
error = TelegramError('test') error = TelegramError('test')
update = Update( update = Update(
0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False)) 0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False))
) )
callback_context = CallbackContext.from_error(update, error, cdp) callback_context = CallbackContext.from_error(update, error, dp)
assert callback_context.error is error assert callback_context.error is error
assert callback_context.chat_data == {} assert callback_context.chat_data == {}
assert callback_context.user_data == {} assert callback_context.user_data == {}
assert callback_context.bot_data is cdp.bot_data assert callback_context.bot_data is dp.bot_data
assert callback_context.bot is cdp.bot assert callback_context.bot is dp.bot
assert callback_context.job_queue is cdp.job_queue assert callback_context.job_queue is dp.job_queue
assert callback_context.update_queue is cdp.update_queue assert callback_context.update_queue is dp.update_queue
assert callback_context.async_args is None assert callback_context.async_args is None
assert callback_context.async_kwargs is None assert callback_context.async_kwargs is None
def test_from_error_async_params(self, cdp): def test_from_error_async_params(self, dp):
error = TelegramError('test') error = TelegramError('test')
args = [1, '2'] args = [1, '2']
kwargs = {'one': 1, 2: 'two'} kwargs = {'one': 1, 2: 'two'}
callback_context = CallbackContext.from_error( callback_context = CallbackContext.from_error(
None, error, cdp, async_args=args, async_kwargs=kwargs None, error, dp, async_args=args, async_kwargs=kwargs
) )
assert callback_context.error is error assert callback_context.error is error
assert callback_context.async_args is args assert callback_context.async_args is args
assert callback_context.async_kwargs is kwargs assert callback_context.async_kwargs is kwargs
def test_match(self, cdp): def test_match(self, dp):
callback_context = CallbackContext(cdp) callback_context = CallbackContext(dp)
assert callback_context.match is None assert callback_context.match is None
@ -159,12 +155,12 @@ class TestCallbackContext:
assert callback_context.match == 'test' assert callback_context.match == 'test'
def test_data_assignment(self, cdp): def test_data_assignment(self, dp):
update = Update( update = Update(
0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False)) 0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False))
) )
callback_context = CallbackContext.from_update(update, cdp) callback_context = CallbackContext.from_update(update, dp)
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
callback_context.bot_data = {"test": 123} callback_context.bot_data = {"test": 123}
@ -173,45 +169,45 @@ class TestCallbackContext:
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
callback_context.chat_data = "test" callback_context.chat_data = "test"
def test_dispatcher_attribute(self, cdp): def test_dispatcher_attribute(self, dp):
callback_context = CallbackContext(cdp) callback_context = CallbackContext(dp)
assert callback_context.dispatcher == cdp assert callback_context.dispatcher == dp
def test_drop_callback_data_exception(self, bot, cdp): def test_drop_callback_data_exception(self, bot, dp):
non_ext_bot = Bot(bot.token) non_ext_bot = Bot(bot.token)
update = Update( update = Update(
0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False)) 0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False))
) )
callback_context = CallbackContext.from_update(update, cdp) callback_context = CallbackContext.from_update(update, dp)
with pytest.raises(RuntimeError, match='This telegram.ext.ExtBot instance does not'): with pytest.raises(RuntimeError, match='This telegram.ext.ExtBot instance does not'):
callback_context.drop_callback_data(None) callback_context.drop_callback_data(None)
try: try:
cdp.bot = non_ext_bot dp.bot = non_ext_bot
with pytest.raises(RuntimeError, match='telegram.Bot does not allow for'): with pytest.raises(RuntimeError, match='telegram.Bot does not allow for'):
callback_context.drop_callback_data(None) callback_context.drop_callback_data(None)
finally: finally:
cdp.bot = bot dp.bot = bot
def test_drop_callback_data(self, cdp, monkeypatch, chat_id): def test_drop_callback_data(self, dp, monkeypatch, chat_id):
monkeypatch.setattr(cdp.bot, 'arbitrary_callback_data', True) monkeypatch.setattr(dp.bot, 'arbitrary_callback_data', True)
update = Update( update = Update(
0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False)) 0, message=Message(0, None, Chat(1, 'chat'), from_user=User(1, 'user', False))
) )
callback_context = CallbackContext.from_update(update, cdp) callback_context = CallbackContext.from_update(update, dp)
cdp.bot.send_message( dp.bot.send_message(
chat_id=chat_id, chat_id=chat_id,
text='test', text='test',
reply_markup=InlineKeyboardMarkup.from_button( reply_markup=InlineKeyboardMarkup.from_button(
InlineKeyboardButton('test', callback_data='callback_data') InlineKeyboardButton('test', callback_data='callback_data')
), ),
) )
keyboard_uuid = cdp.bot.callback_data_cache.persistence_data[0][0][0] keyboard_uuid = dp.bot.callback_data_cache.persistence_data[0][0][0]
button_uuid = list(cdp.bot.callback_data_cache.persistence_data[0][0][2])[0] button_uuid = list(dp.bot.callback_data_cache.persistence_data[0][0][2])[0]
callback_data = keyboard_uuid + button_uuid callback_data = keyboard_uuid + button_uuid
callback_query = CallbackQuery( callback_query = CallbackQuery(
id='1', id='1',
@ -219,14 +215,14 @@ class TestCallbackContext:
chat_instance=None, chat_instance=None,
data=callback_data, data=callback_data,
) )
cdp.bot.callback_data_cache.process_callback_query(callback_query) dp.bot.callback_data_cache.process_callback_query(callback_query)
try: try:
assert len(cdp.bot.callback_data_cache.persistence_data[0]) == 1 assert len(dp.bot.callback_data_cache.persistence_data[0]) == 1
assert list(cdp.bot.callback_data_cache.persistence_data[1]) == ['1'] assert list(dp.bot.callback_data_cache.persistence_data[1]) == ['1']
callback_context.drop_callback_data(callback_query) callback_context.drop_callback_data(callback_query)
assert cdp.bot.callback_data_cache.persistence_data == ([], {}) assert dp.bot.callback_data_cache.persistence_data == ([], {})
finally: finally:
cdp.bot.callback_data_cache.clear_callback_data() dp.bot.callback_data_cache.clear_callback_data()
cdp.bot.callback_data_cache.clear_callback_queries() dp.bot.callback_data_cache.clear_callback_queries()

View file

@ -82,8 +82,8 @@ class TestCallbackQueryHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update): def callback_basic(self, update, context):
test_bot = isinstance(bot, Bot) test_bot = isinstance(context.bot, Bot)
test_update = isinstance(update, Update) test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update self.test_flag = test_bot and test_update
@ -124,15 +124,6 @@ class TestCallbackQueryHandler:
if context.matches[0].groupdict(): if context.matches[0].groupdict():
self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' data'} self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' data'}
def test_basic(self, dp, callback_query):
handler = CallbackQueryHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(callback_query)
dp.process_update(callback_query)
assert self.test_flag
def test_with_pattern(self, callback_query): def test_with_pattern(self, callback_query):
handler = CallbackQueryHandler(self.callback_basic, pattern='.*est.*') handler = CallbackQueryHandler(self.callback_basic, pattern='.*est.*')
@ -177,103 +168,34 @@ class TestCallbackQueryHandler:
callback_query.callback_query.data = 'callback_data' callback_query.callback_query.data = 'callback_data'
assert not handler.check_update(callback_query) assert not handler.check_update(callback_query)
def test_with_passing_group_dict(self, dp, callback_query):
handler = CallbackQueryHandler(
self.callback_group, pattern='(?P<begin>.*)est(?P<end>.*)', pass_groups=True
)
dp.add_handler(handler)
dp.process_update(callback_query)
assert self.test_flag
dp.remove_handler(handler)
handler = CallbackQueryHandler(
self.callback_group, pattern='(?P<begin>.*)est(?P<end>.*)', pass_groupdict=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(callback_query)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, callback_query):
handler = CallbackQueryHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(callback_query)
assert self.test_flag
dp.remove_handler(handler)
handler = CallbackQueryHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(callback_query)
assert self.test_flag
dp.remove_handler(handler)
handler = CallbackQueryHandler(
self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(callback_query)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, callback_query):
handler = CallbackQueryHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(callback_query)
assert self.test_flag
dp.remove_handler(handler)
handler = CallbackQueryHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(callback_query)
assert self.test_flag
dp.remove_handler(handler)
handler = CallbackQueryHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(callback_query)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = CallbackQueryHandler(self.callback_basic) handler = CallbackQueryHandler(self.callback_basic)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, callback_query): def test_context(self, dp, callback_query):
handler = CallbackQueryHandler(self.callback_context) handler = CallbackQueryHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(callback_query) dp.process_update(callback_query)
assert self.test_flag assert self.test_flag
def test_context_pattern(self, cdp, callback_query): def test_context_pattern(self, dp, callback_query):
handler = CallbackQueryHandler( handler = CallbackQueryHandler(
self.callback_context_pattern, pattern=r'(?P<begin>.*)est(?P<end>.*)' self.callback_context_pattern, pattern=r'(?P<begin>.*)est(?P<end>.*)'
) )
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(callback_query) dp.process_update(callback_query)
assert self.test_flag assert self.test_flag
cdp.remove_handler(handler) dp.remove_handler(handler)
handler = CallbackQueryHandler(self.callback_context_pattern, pattern=r'(t)est(.*)') handler = CallbackQueryHandler(self.callback_context_pattern, pattern=r'(t)est(.*)')
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(callback_query) dp.process_update(callback_query)
assert self.test_flag assert self.test_flag
def test_context_callable_pattern(self, cdp, callback_query): def test_context_callable_pattern(self, dp, callback_query):
class CallbackData: class CallbackData:
pass pass
@ -284,6 +206,6 @@ class TestCallbackQueryHandler:
assert context.matches is None assert context.matches is None
handler = CallbackQueryHandler(callback, pattern=pattern) handler = CallbackQueryHandler(callback, pattern=pattern)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(callback_query) dp.process_update(callback_query)

View file

@ -102,7 +102,7 @@ class TestChatJoinRequestHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, recwarn, mro_slots): def test_slot_behaviour(self, recwarn, mro_slots):
action = ChatJoinRequestHandler(self.callback_basic) action = ChatJoinRequestHandler(self.callback_context)
for attr in action.__slots__: for attr in action.__slots__:
assert getattr(action, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(action, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot" assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
@ -111,23 +111,6 @@ class TestChatJoinRequestHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -144,73 +127,14 @@ class TestChatJoinRequestHandler:
) )
) )
def test_basic(self, dp, chat_join_request_update):
handler = ChatJoinRequestHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(chat_join_request_update)
dp.process_update(chat_join_request_update)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, chat_join_request_update):
handler = ChatJoinRequestHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(chat_join_request_update)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatJoinRequestHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_join_request_update)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatJoinRequestHandler(
self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_join_request_update)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, chat_join_request_update):
handler = ChatJoinRequestHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(chat_join_request_update)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatJoinRequestHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_join_request_update)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatJoinRequestHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_join_request_update)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = ChatJoinRequestHandler(self.callback_basic) handler = ChatJoinRequestHandler(self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
assert not handler.check_update(True) assert not handler.check_update(True)
def test_context(self, cdp, chat_join_request_update): def test_context(self, dp, chat_join_request_update):
handler = ChatJoinRequestHandler(callback=self.callback_context) handler = ChatJoinRequestHandler(callback=self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(chat_join_request_update) dp.process_update(chat_join_request_update)
assert self.test_flag assert self.test_flag

View file

@ -89,7 +89,7 @@ class TestChatMemberHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
action = ChatMemberHandler(self.callback_basic) action = ChatMemberHandler(self.callback_context)
for attr in action.__slots__: for attr in action.__slots__:
assert getattr(action, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(action, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot" assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
@ -98,23 +98,6 @@ class TestChatMemberHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -128,15 +111,6 @@ class TestChatMemberHandler:
and isinstance(update.chat_member or update.my_chat_member, ChatMemberUpdated) and isinstance(update.chat_member or update.my_chat_member, ChatMemberUpdated)
) )
def test_basic(self, dp, chat_member):
handler = ChatMemberHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(chat_member)
dp.process_update(chat_member)
assert self.test_flag
@pytest.mark.parametrize( @pytest.mark.parametrize(
argnames=['allowed_types', 'expected'], argnames=['allowed_types', 'expected'],
argvalues=[ argvalues=[
@ -151,7 +125,7 @@ class TestChatMemberHandler:
): ):
result_1, result_2 = expected result_1, result_2 = expected
handler = ChatMemberHandler(self.callback_basic, chat_member_types=allowed_types) handler = ChatMemberHandler(self.callback_context, chat_member_types=allowed_types)
dp.add_handler(handler) dp.add_handler(handler)
assert handler.check_update(chat_member) == result_1 assert handler.check_update(chat_member) == result_1
@ -166,62 +140,14 @@ class TestChatMemberHandler:
dp.process_update(chat_member) dp.process_update(chat_member)
assert self.test_flag == result_2 assert self.test_flag == result_2
def test_pass_user_or_chat_data(self, dp, chat_member):
handler = ChatMemberHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(chat_member)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatMemberHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_member)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatMemberHandler(self.callback_data_2, pass_chat_data=True, pass_user_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_member)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, chat_member):
handler = ChatMemberHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(chat_member)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatMemberHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_member)
assert self.test_flag
dp.remove_handler(handler)
handler = ChatMemberHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chat_member)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = ChatMemberHandler(self.callback_basic) handler = ChatMemberHandler(self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
assert not handler.check_update(True) assert not handler.check_update(True)
def test_context(self, cdp, chat_member): def test_context(self, dp, chat_member):
handler = ChatMemberHandler(self.callback_context) handler = ChatMemberHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(chat_member) dp.process_update(chat_member)
assert self.test_flag assert self.test_flag

View file

@ -87,8 +87,8 @@ class TestChosenInlineResultHandler:
assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot" assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
def callback_basic(self, bot, update): def callback_basic(self, update, context):
test_bot = isinstance(bot, Bot) test_bot = isinstance(context.bot, Bot)
test_update = isinstance(update, Update) test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update self.test_flag = test_bot and test_update
@ -123,73 +123,15 @@ class TestChosenInlineResultHandler:
if context.matches[0].groupdict(): if context.matches[0].groupdict():
self.test_flag = context.matches[0].groupdict() == {'begin': 'res', 'end': '_id'} 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)
assert handler.check_update(chosen_inline_result)
dp.process_update(chosen_inline_result)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, chosen_inline_result):
handler = ChosenInlineResultHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(chosen_inline_result)
assert self.test_flag
dp.remove_handler(handler)
handler = ChosenInlineResultHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chosen_inline_result)
assert self.test_flag
dp.remove_handler(handler)
handler = ChosenInlineResultHandler(
self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chosen_inline_result)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, chosen_inline_result):
handler = ChosenInlineResultHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(chosen_inline_result)
assert self.test_flag
dp.remove_handler(handler)
handler = ChosenInlineResultHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chosen_inline_result)
assert self.test_flag
dp.remove_handler(handler)
handler = ChosenInlineResultHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(chosen_inline_result)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = ChosenInlineResultHandler(self.callback_basic) handler = ChosenInlineResultHandler(self.callback_basic)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, chosen_inline_result): def test_context(self, dp, chosen_inline_result):
handler = ChosenInlineResultHandler(self.callback_context) handler = ChosenInlineResultHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(chosen_inline_result) dp.process_update(chosen_inline_result)
assert self.test_flag assert self.test_flag
def test_with_pattern(self, chosen_inline_result): def test_with_pattern(self, chosen_inline_result):
@ -201,17 +143,17 @@ class TestChosenInlineResultHandler:
assert not handler.check_update(chosen_inline_result) assert not handler.check_update(chosen_inline_result)
chosen_inline_result.chosen_inline_result.result_id = 'result_id' chosen_inline_result.chosen_inline_result.result_id = 'result_id'
def test_context_pattern(self, cdp, chosen_inline_result): def test_context_pattern(self, dp, chosen_inline_result):
handler = ChosenInlineResultHandler( handler = ChosenInlineResultHandler(
self.callback_context_pattern, pattern=r'(?P<begin>.*)ult(?P<end>.*)' self.callback_context_pattern, pattern=r'(?P<begin>.*)ult(?P<end>.*)'
) )
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(chosen_inline_result) dp.process_update(chosen_inline_result)
assert self.test_flag assert self.test_flag
cdp.remove_handler(handler) dp.remove_handler(handler)
handler = ChosenInlineResultHandler(self.callback_context_pattern, pattern=r'(res)ult(.*)') handler = ChosenInlineResultHandler(self.callback_context_pattern, pattern=r'(res)ult(.*)')
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(chosen_inline_result) dp.process_update(chosen_inline_result)
assert self.test_flag assert self.test_flag

View file

@ -20,8 +20,6 @@ import re
from queue import Queue from queue import Queue
import pytest import pytest
import itertools
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram import Message, Update, Chat, Bot from telegram import Message, Update, Chat, Bot
from telegram.ext import CommandHandler, Filters, CallbackContext, JobQueue, PrefixHandler from telegram.ext import CommandHandler, Filters, CallbackContext, JobQueue, PrefixHandler
@ -56,12 +54,6 @@ class BaseTest:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
PASS_KEYWORDS = ('pass_user_data', 'pass_chat_data', 'pass_job_queue', 'pass_update_queue')
@pytest.fixture(scope='module', params=itertools.combinations(PASS_KEYWORDS, 2))
def pass_combination(self, request):
return {key: True for key in request.param}
def response(self, dispatcher, update): def response(self, dispatcher, update):
""" """
Utility to send an update to a dispatcher and assert Utility to send an update to a dispatcher and assert
@ -72,8 +64,8 @@ class BaseTest:
dispatcher.process_update(update) dispatcher.process_update(update)
return self.test_flag return self.test_flag
def callback_basic(self, bot, update): def callback_basic(self, update, context):
test_bot = isinstance(bot, Bot) test_bot = isinstance(context.bot, Bot)
test_update = isinstance(update, Update) test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update self.test_flag = test_bot and test_update
@ -112,12 +104,12 @@ class BaseTest:
num = len(context.matches) == 2 num = len(context.matches) == 2
self.test_flag = types and num self.test_flag = types and num
def _test_context_args_or_regex(self, cdp, handler, text): def _test_context_args_or_regex(self, dp, handler, text):
cdp.add_handler(handler) dp.add_handler(handler)
update = make_command_update(text) update = make_command_update(text)
assert not self.response(cdp, update) assert not self.response(dp, update)
update.message.text += ' one two' update.message.text += ' one two'
assert self.response(cdp, update) assert self.response(dp, update)
def _test_edited(self, message, handler_edited, handler_not_edited): def _test_edited(self, message, handler_edited, handler_not_edited):
""" """
@ -160,14 +152,6 @@ class TestCommandHandler(BaseTest):
def command_update(self, command_message): def command_update(self, command_message):
return make_command_update(command_message) return make_command_update(command_message)
def ch_callback_args(self, bot, update, args):
if update.message.text == self.CMD:
self.test_flag = len(args) == 0
elif update.message.text == f'{self.CMD}@{bot.username}':
self.test_flag = len(args) == 0
else:
self.test_flag = args == ['one', 'two']
def make_default_handler(self, callback=None, **kwargs): def make_default_handler(self, callback=None, **kwargs):
callback = callback or self.callback_basic callback = callback or self.callback_basic
return CommandHandler(self.CMD[1:], callback, **kwargs) return CommandHandler(self.CMD[1:], callback, **kwargs)
@ -199,23 +183,12 @@ class TestCommandHandler(BaseTest):
assert is_match(handler, make_command_update('/star')) assert is_match(handler, make_command_update('/star'))
assert not is_match(handler, make_command_update('/stop')) assert not is_match(handler, make_command_update('/stop'))
def test_deprecation_warning(self):
"""``allow_edited`` deprecated in favor of filters"""
with pytest.warns(TelegramDeprecationWarning, match='See https://git.io/fxJuV'):
self.make_default_handler(allow_edited=True)
def test_edited(self, command_message): def test_edited(self, command_message):
"""Test that a CH responds to an edited message iff its filters allow it""" """Test that a CH responds to an edited message if its filters allow it"""
handler_edited = self.make_default_handler() handler_edited = self.make_default_handler()
handler_no_edited = self.make_default_handler(filters=~Filters.update.edited_message) handler_no_edited = self.make_default_handler(filters=~Filters.update.edited_message)
self._test_edited(command_message, handler_edited, handler_no_edited) self._test_edited(command_message, handler_edited, handler_no_edited)
def test_edited_deprecated(self, command_message):
"""Test that a CH responds to an edited message iff ``allow_edited`` is True"""
handler_edited = self.make_default_handler(allow_edited=True)
handler_no_edited = self.make_default_handler(allow_edited=False)
self._test_edited(command_message, handler_edited, handler_no_edited)
def test_directed_commands(self, bot, command): def test_directed_commands(self, bot, command):
"""Test recognition of commands with a mention to the bot""" """Test recognition of commands with a mention to the bot"""
handler = self.make_default_handler() handler = self.make_default_handler()
@ -223,21 +196,11 @@ class TestCommandHandler(BaseTest):
assert not is_match(handler, make_command_update(command + '@otherbot', bot=bot)) assert not is_match(handler, make_command_update(command + '@otherbot', bot=bot))
def test_with_filter(self, command): def test_with_filter(self, command):
"""Test that a CH with a (generic) filter responds iff its filters match""" """Test that a CH with a (generic) filter responds if its filters match"""
handler = self.make_default_handler(filters=Filters.group) handler = self.make_default_handler(filters=Filters.group)
assert is_match(handler, make_command_update(command, chat=Chat(-23, Chat.GROUP))) assert is_match(handler, make_command_update(command, chat=Chat(-23, Chat.GROUP)))
assert not is_match(handler, make_command_update(command, chat=Chat(23, Chat.PRIVATE))) assert not is_match(handler, make_command_update(command, chat=Chat(23, Chat.PRIVATE)))
def test_pass_args(self, dp, bot, command):
"""Test the passing of arguments alongside a command"""
handler = self.make_default_handler(self.ch_callback_args, pass_args=True)
dp.add_handler(handler)
at_command = f'{command}@{bot.username}'
assert self.response(dp, make_command_update(command))
assert self.response(dp, make_command_update(command + ' one two'))
assert self.response(dp, make_command_update(at_command, bot=bot))
assert self.response(dp, make_command_update(at_command + ' one two', bot=bot))
def test_newline(self, dp, command): def test_newline(self, dp, command):
"""Assert that newlines don't interfere with a command handler matching a message""" """Assert that newlines don't interfere with a command handler matching a message"""
handler = self.make_default_handler() handler = self.make_default_handler()
@ -246,12 +209,6 @@ class TestCommandHandler(BaseTest):
assert is_match(handler, update) assert is_match(handler, update)
assert self.response(dp, update) assert self.response(dp, update)
@pytest.mark.parametrize('pass_keyword', BaseTest.PASS_KEYWORDS)
def test_pass_data(self, dp, command_update, pass_combination, pass_keyword):
handler = CommandHandler('test', self.make_callback_for(pass_keyword), **pass_combination)
dp.add_handler(handler)
assert self.response(dp, command_update) == pass_combination.get(pass_keyword, False)
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
"""Test that a command handler doesn't respond to unrelated updates""" """Test that a command handler doesn't respond to unrelated updates"""
handler = self.make_default_handler() handler = self.make_default_handler()
@ -263,30 +220,30 @@ class TestCommandHandler(BaseTest):
assert not is_match(handler, make_command_update('/star')) assert not is_match(handler, make_command_update('/star'))
assert not mock_filter.tested assert not mock_filter.tested
def test_context(self, cdp, command_update): def test_context(self, dp, command_update):
"""Test correct behaviour of CHs with context-based callbacks""" """Test correct behaviour of CHs with context-based callbacks"""
handler = self.make_default_handler(self.callback_context) handler = self.make_default_handler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
assert self.response(cdp, command_update) assert self.response(dp, command_update)
def test_context_args(self, cdp, command): def test_context_args(self, dp, command):
"""Test CHs that pass arguments through ``context``""" """Test CHs that pass arguments through ``context``"""
handler = self.make_default_handler(self.callback_context_args) handler = self.make_default_handler(self.callback_context_args)
self._test_context_args_or_regex(cdp, handler, command) self._test_context_args_or_regex(dp, handler, command)
def test_context_regex(self, cdp, command): def test_context_regex(self, dp, command):
"""Test CHs with context-based callbacks and a single filter""" """Test CHs with context-based callbacks and a single filter"""
handler = self.make_default_handler( handler = self.make_default_handler(
self.callback_context_regex1, filters=Filters.regex('one two') self.callback_context_regex1, filters=Filters.regex('one two')
) )
self._test_context_args_or_regex(cdp, handler, command) self._test_context_args_or_regex(dp, handler, command)
def test_context_multiple_regex(self, cdp, command): def test_context_multiple_regex(self, dp, command):
"""Test CHs with context-based callbacks and filters combined""" """Test CHs with context-based callbacks and filters combined"""
handler = self.make_default_handler( handler = self.make_default_handler(
self.callback_context_regex2, filters=Filters.regex('one') & Filters.regex('two') self.callback_context_regex2, filters=Filters.regex('one') & Filters.regex('two')
) )
self._test_context_args_or_regex(cdp, handler, command) self._test_context_args_or_regex(dp, handler, command)
# ----------------------------- PrefixHandler ----------------------------- # ----------------------------- PrefixHandler -----------------------------
@ -340,12 +297,6 @@ class TestPrefixHandler(BaseTest):
callback = callback or self.callback_basic callback = callback or self.callback_basic
return PrefixHandler(self.PREFIXES, self.COMMANDS, callback, **kwargs) return PrefixHandler(self.PREFIXES, self.COMMANDS, callback, **kwargs)
def ch_callback_args(self, bot, update, args):
if update.message.text in TestPrefixHandler.COMBINATIONS:
self.test_flag = len(args) == 0
else:
self.test_flag = args == ['one', 'two']
def test_basic(self, dp, prefix, command): def test_basic(self, dp, prefix, command):
"""Test the basic expected response from a prefix handler""" """Test the basic expected response from a prefix handler"""
handler = self.make_default_handler() handler = self.make_default_handler()
@ -375,25 +326,6 @@ class TestPrefixHandler(BaseTest):
assert is_match(handler, make_message_update(text, chat=Chat(-23, Chat.GROUP))) assert is_match(handler, make_message_update(text, chat=Chat(-23, Chat.GROUP)))
assert not is_match(handler, make_message_update(text, chat=Chat(23, Chat.PRIVATE))) assert not is_match(handler, make_message_update(text, chat=Chat(23, Chat.PRIVATE)))
def test_pass_args(self, dp, prefix_message):
handler = self.make_default_handler(self.ch_callback_args, pass_args=True)
dp.add_handler(handler)
assert self.response(dp, make_message_update(prefix_message))
update_with_args = make_message_update(prefix_message.text + ' one two')
assert self.response(dp, update_with_args)
@pytest.mark.parametrize('pass_keyword', BaseTest.PASS_KEYWORDS)
def test_pass_data(self, dp, pass_combination, prefix_message_update, pass_keyword):
"""Assert that callbacks receive data iff its corresponding ``pass_*`` kwarg is enabled"""
handler = self.make_default_handler(
self.make_callback_for(pass_keyword), **pass_combination
)
dp.add_handler(handler)
assert self.response(dp, prefix_message_update) == pass_combination.get(
pass_keyword, False
)
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = self.make_default_handler() handler = self.make_default_handler()
assert not is_match(handler, false_update) assert not is_match(handler, false_update)
@ -427,23 +359,23 @@ class TestPrefixHandler(BaseTest):
text = prefix + 'foo' text = prefix + 'foo'
assert self.response(dp, make_message_update(text)) assert self.response(dp, make_message_update(text))
def test_context(self, cdp, prefix_message_update): def test_context(self, dp, prefix_message_update):
handler = self.make_default_handler(self.callback_context) handler = self.make_default_handler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
assert self.response(cdp, prefix_message_update) assert self.response(dp, prefix_message_update)
def test_context_args(self, cdp, prefix_message_text): def test_context_args(self, dp, prefix_message_text):
handler = self.make_default_handler(self.callback_context_args) handler = self.make_default_handler(self.callback_context_args)
self._test_context_args_or_regex(cdp, handler, prefix_message_text) self._test_context_args_or_regex(dp, handler, prefix_message_text)
def test_context_regex(self, cdp, prefix_message_text): def test_context_regex(self, dp, prefix_message_text):
handler = self.make_default_handler( handler = self.make_default_handler(
self.callback_context_regex1, filters=Filters.regex('one two') self.callback_context_regex1, filters=Filters.regex('one two')
) )
self._test_context_args_or_regex(cdp, handler, prefix_message_text) self._test_context_args_or_regex(dp, handler, prefix_message_text)
def test_context_multiple_regex(self, cdp, prefix_message_text): def test_context_multiple_regex(self, dp, prefix_message_text):
handler = self.make_default_handler( handler = self.make_default_handler(
self.callback_context_regex2, filters=Filters.regex('one') & Filters.regex('two') self.callback_context_regex2, filters=Filters.regex('one') & Filters.regex('two')
) )
self._test_context_args_or_regex(cdp, handler, prefix_message_text) self._test_context_args_or_regex(dp, handler, prefix_message_text)

View file

@ -170,45 +170,45 @@ class TestConversationHandler:
# Actions # Actions
@raise_dphs @raise_dphs
def start(self, bot, update): def start(self, update, context):
if isinstance(update, Update): if isinstance(update, Update):
return self._set_state(update, self.THIRSTY) return self._set_state(update, self.THIRSTY)
return self._set_state(bot, self.THIRSTY) return self._set_state(context.bot, self.THIRSTY)
@raise_dphs @raise_dphs
def end(self, bot, update): def end(self, update, context):
return self._set_state(update, self.END) return self._set_state(update, self.END)
@raise_dphs @raise_dphs
def start_end(self, bot, update): def start_end(self, update, context):
return self._set_state(update, self.END) return self._set_state(update, self.END)
@raise_dphs @raise_dphs
def start_none(self, bot, update): def start_none(self, update, context):
return self._set_state(update, None) return self._set_state(update, None)
@raise_dphs @raise_dphs
def brew(self, bot, update): def brew(self, update, context):
if isinstance(update, Update): if isinstance(update, Update):
return self._set_state(update, self.BREWING) return self._set_state(update, self.BREWING)
return self._set_state(bot, self.BREWING) return self._set_state(context.bot, self.BREWING)
@raise_dphs @raise_dphs
def drink(self, bot, update): def drink(self, update, context):
return self._set_state(update, self.DRINKING) return self._set_state(update, self.DRINKING)
@raise_dphs @raise_dphs
def code(self, bot, update): def code(self, update, context):
return self._set_state(update, self.CODING) return self._set_state(update, self.CODING)
@raise_dphs @raise_dphs
def passout(self, bot, update): def passout(self, update, context):
assert update.message.text == '/brew' assert update.message.text == '/brew'
assert isinstance(update, Update) assert isinstance(update, Update)
self.is_timeout = True self.is_timeout = True
@raise_dphs @raise_dphs
def passout2(self, bot, update): def passout2(self, update, context):
assert isinstance(update, Update) assert isinstance(update, Update)
self.is_timeout = True self.is_timeout = True
@ -226,23 +226,23 @@ class TestConversationHandler:
# Drinking actions (nested) # Drinking actions (nested)
@raise_dphs @raise_dphs
def hold(self, bot, update): def hold(self, update, context):
return self._set_state(update, self.HOLDING) return self._set_state(update, self.HOLDING)
@raise_dphs @raise_dphs
def sip(self, bot, update): def sip(self, update, context):
return self._set_state(update, self.SIPPING) return self._set_state(update, self.SIPPING)
@raise_dphs @raise_dphs
def swallow(self, bot, update): def swallow(self, update, context):
return self._set_state(update, self.SWALLOWING) return self._set_state(update, self.SWALLOWING)
@raise_dphs @raise_dphs
def replenish(self, bot, update): def replenish(self, update, context):
return self._set_state(update, self.REPLENISHING) return self._set_state(update, self.REPLENISHING)
@raise_dphs @raise_dphs
def stop(self, bot, update): def stop(self, update, context):
return self._set_state(update, self.STOPPING) return self._set_state(update, self.STOPPING)
# Tests # Tests
@ -543,13 +543,13 @@ class TestConversationHandler:
assert handler.conversations[(user1.id,)] == self.DRINKING assert handler.conversations[(user1.id,)] == self.DRINKING
def test_conversation_handler_per_message(self, dp, bot, user1, user2): def test_conversation_handler_per_message(self, dp, bot, user1, user2):
def entry(bot, update): def entry(update, context):
return 1 return 1
def one(bot, update): def one(update, context):
return 2 return 2
def two(bot, update): def two(update, context):
return ConversationHandler.END return ConversationHandler.END
handler = ConversationHandler( handler = ConversationHandler(
@ -606,7 +606,7 @@ class TestConversationHandler:
handler = ConversationHandler( handler = ConversationHandler(
entry_points=[ entry_points=[
CommandHandler( CommandHandler(
'start', lambda bot, update: dp.run_async(self.start_end, bot, update) 'start', lambda update, context: dp.run_async(self.start_end, update, context)
) )
], ],
states={}, states={},
@ -687,7 +687,7 @@ class TestConversationHandler:
handler = ConversationHandler( handler = ConversationHandler(
entry_points=[ entry_points=[
CommandHandler( CommandHandler(
'start', lambda bot, update: dp.run_async(self.start_none, bot, update) 'start', lambda update, context: dp.run_async(self.start_none, update, context)
) )
], ],
states={}, states={},
@ -1026,7 +1026,7 @@ class TestConversationHandler:
rec = caplog.records[-1] rec = caplog.records[-1]
assert rec.getMessage().startswith('DispatcherHandlerStop in TIMEOUT') assert rec.getMessage().startswith('DispatcherHandlerStop in TIMEOUT')
def test_conversation_handler_timeout_update_and_context(self, cdp, bot, user1): def test_conversation_handler_timeout_update_and_context(self, dp, bot, user1):
context = None context = None
def start_callback(u, c): def start_callback(u, c):
@ -1043,7 +1043,7 @@ class TestConversationHandler:
fallbacks=self.fallbacks, fallbacks=self.fallbacks,
conversation_timeout=0.5, conversation_timeout=0.5,
) )
cdp.add_handler(handler) dp.add_handler(handler)
# Start state machine, then reach timeout # Start state machine, then reach timeout
message = Message( message = Message(
@ -1067,7 +1067,7 @@ class TestConversationHandler:
timeout_handler.callback = timeout_callback timeout_handler.callback = timeout_callback
cdp.process_update(update) dp.process_update(update)
sleep(0.7) sleep(0.7)
assert handler.conversations.get((self.group.id, user1.id)) is None assert handler.conversations.get((self.group.id, user1.id)) is None
assert self.is_timeout assert self.is_timeout
@ -1216,7 +1216,7 @@ class TestConversationHandler:
assert handler.conversations.get((self.group.id, user1.id)) is None assert handler.conversations.get((self.group.id, user1.id)) is None
assert not self.is_timeout assert not self.is_timeout
def test_conversation_handler_timeout_state_context(self, cdp, bot, user1): def test_conversation_handler_timeout_state_context(self, dp, bot, user1):
states = self.states states = self.states
states.update( states.update(
{ {
@ -1232,7 +1232,7 @@ class TestConversationHandler:
fallbacks=self.fallbacks, fallbacks=self.fallbacks,
conversation_timeout=0.5, conversation_timeout=0.5,
) )
cdp.add_handler(handler) dp.add_handler(handler)
# CommandHandler timeout # CommandHandler timeout
message = Message( message = Message(
@ -1246,10 +1246,10 @@ class TestConversationHandler:
], ],
bot=bot, bot=bot,
) )
cdp.process_update(Update(update_id=0, message=message)) dp.process_update(Update(update_id=0, message=message))
message.text = '/brew' message.text = '/brew'
message.entities[0].length = len('/brew') message.entities[0].length = len('/brew')
cdp.process_update(Update(update_id=0, message=message)) dp.process_update(Update(update_id=0, message=message))
sleep(0.7) sleep(0.7)
assert handler.conversations.get((self.group.id, user1.id)) is None assert handler.conversations.get((self.group.id, user1.id)) is None
assert self.is_timeout assert self.is_timeout
@ -1258,20 +1258,20 @@ class TestConversationHandler:
self.is_timeout = False self.is_timeout = False
message.text = '/start' message.text = '/start'
message.entities[0].length = len('/start') message.entities[0].length = len('/start')
cdp.process_update(Update(update_id=1, message=message)) dp.process_update(Update(update_id=1, message=message))
sleep(0.7) sleep(0.7)
assert handler.conversations.get((self.group.id, user1.id)) is None assert handler.conversations.get((self.group.id, user1.id)) is None
assert self.is_timeout assert self.is_timeout
# Timeout but no valid handler # Timeout but no valid handler
self.is_timeout = False self.is_timeout = False
cdp.process_update(Update(update_id=0, message=message)) dp.process_update(Update(update_id=0, message=message))
message.text = '/brew' message.text = '/brew'
message.entities[0].length = len('/brew') message.entities[0].length = len('/brew')
cdp.process_update(Update(update_id=0, message=message)) dp.process_update(Update(update_id=0, message=message))
message.text = '/startCoding' message.text = '/startCoding'
message.entities[0].length = len('/startCoding') message.entities[0].length = len('/startCoding')
cdp.process_update(Update(update_id=0, message=message)) dp.process_update(Update(update_id=0, message=message))
sleep(0.7) sleep(0.7)
assert handler.conversations.get((self.group.id, user1.id)) is None assert handler.conversations.get((self.group.id, user1.id)) is None
assert not self.is_timeout assert not self.is_timeout
@ -1285,7 +1285,7 @@ class TestConversationHandler:
# | t=.75 /slowbrew returns (timeout=1.25) # | t=.75 /slowbrew returns (timeout=1.25)
# t=1.25 timeout # t=1.25 timeout
def slowbrew(_bot, update): def slowbrew(_update, context):
sleep(0.25) sleep(0.25)
# Let's give to the original timeout a chance to execute # Let's give to the original timeout a chance to execute
sleep(0.25) sleep(0.25)
@ -1395,10 +1395,10 @@ class TestConversationHandler:
) )
def test_warnings_per_chat_is_only_shown_once(self, recwarn): def test_warnings_per_chat_is_only_shown_once(self, recwarn):
def hello(bot, update): def hello(update, context):
return self.BREWING return self.BREWING
def bye(bot, update): def bye(update, context):
return ConversationHandler.END return ConversationHandler.END
ConversationHandler( ConversationHandler(

View file

@ -30,7 +30,7 @@ class TestDefault:
assert getattr(a, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(a, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(a)) == len(set(mro_slots(a))), "duplicate slot" assert len(mro_slots(a)) == len(set(mro_slots(a))), "duplicate slot"
def test_data_assignment(self, cdp): def test_data_assignment(self, dp):
defaults = Defaults() defaults = Defaults()
with pytest.raises(AttributeError): with pytest.raises(AttributeError):

View file

@ -72,16 +72,13 @@ class TestDispatcher:
self.received = None self.received = None
self.count = 0 self.count = 0
def error_handler(self, bot, update, error):
self.received = error.message
def error_handler_context(self, update, context): def error_handler_context(self, update, context):
self.received = context.error.message self.received = context.error.message
def error_handler_raise_error(self, bot, update, error): def error_handler_raise_error(self, update, context):
raise Exception('Failing bigly') raise Exception('Failing bigly')
def callback_increase_count(self, bot, update): def callback_increase_count(self, update, context):
self.count += 1 self.count += 1
def callback_set_count(self, count): def callback_set_count(self, count):
@ -90,13 +87,10 @@ class TestDispatcher:
return callback return callback
def callback_raise_error(self, bot, update): def callback_raise_error(self, update, context):
if isinstance(bot, Bot):
raise TelegramError(update.message.text) raise TelegramError(update.message.text)
raise TelegramError(bot.message.text)
def callback_if_not_update_queue(self, bot, update, update_queue=None): def callback_received(self, update, context):
if update_queue is not None:
self.received = update.message self.received = update.message
def callback_context(self, update, context): def callback_context(self, update, context):
@ -110,14 +104,14 @@ class TestDispatcher:
self.received = context.error.message self.received = context.error.message
def test_less_than_one_worker_warning(self, dp, recwarn): def test_less_than_one_worker_warning(self, dp, recwarn):
Dispatcher(dp.bot, dp.update_queue, job_queue=dp.job_queue, workers=0, use_context=True) Dispatcher(dp.bot, dp.update_queue, job_queue=dp.job_queue, workers=0)
assert len(recwarn) == 1 assert len(recwarn) == 1
assert ( assert (
str(recwarn[0].message) str(recwarn[0].message)
== 'Asynchronous callbacks can not be processed without at least one worker thread.' == 'Asynchronous callbacks can not be processed without at least one worker thread.'
) )
def test_one_context_per_update(self, cdp): def test_one_context_per_update(self, dp):
def one(update, context): def one(update, context):
if update.message.text == 'test': if update.message.text == 'test':
context.my_flag = True context.my_flag = True
@ -130,22 +124,22 @@ class TestDispatcher:
if hasattr(context, 'my_flag'): if hasattr(context, 'my_flag'):
pytest.fail() pytest.fail()
cdp.add_handler(MessageHandler(Filters.regex('test'), one), group=1) dp.add_handler(MessageHandler(Filters.regex('test'), one), group=1)
cdp.add_handler(MessageHandler(None, two), group=2) dp.add_handler(MessageHandler(None, two), group=2)
u = Update(1, Message(1, None, None, None, text='test')) u = Update(1, Message(1, None, None, None, text='test'))
cdp.process_update(u) dp.process_update(u)
u.message.text = 'something' u.message.text = 'something'
cdp.process_update(u) dp.process_update(u)
def test_error_handler(self, dp): def test_error_handler(self, dp):
dp.add_error_handler(self.error_handler) dp.add_error_handler(self.error_handler_context)
error = TelegramError('Unauthorized.') error = TelegramError('Unauthorized.')
dp.update_queue.put(error) dp.update_queue.put(error)
sleep(0.1) sleep(0.1)
assert self.received == 'Unauthorized.' assert self.received == 'Unauthorized.'
# Remove handler # Remove handler
dp.remove_error_handler(self.error_handler) dp.remove_error_handler(self.error_handler_context)
self.reset() self.reset()
dp.update_queue.put(error) dp.update_queue.put(error)
@ -153,9 +147,9 @@ class TestDispatcher:
assert self.received is None assert self.received is None
def test_double_add_error_handler(self, dp, caplog): def test_double_add_error_handler(self, dp, caplog):
dp.add_error_handler(self.error_handler) dp.add_error_handler(self.error_handler_context)
with caplog.at_level(logging.DEBUG): with caplog.at_level(logging.DEBUG):
dp.add_error_handler(self.error_handler) dp.add_error_handler(self.error_handler_context)
assert len(caplog.records) == 1 assert len(caplog.records) == 1
assert caplog.records[-1].getMessage().startswith('The callback is already registered') assert caplog.records[-1].getMessage().startswith('The callback is already registered')
@ -202,7 +196,7 @@ class TestDispatcher:
dp.bot.defaults = Defaults(run_async=run_async) dp.bot.defaults = Defaults(run_async=run_async)
try: try:
dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error)) dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error))
dp.add_error_handler(self.error_handler) dp.add_error_handler(self.error_handler_context)
monkeypatch.setattr(dp, 'run_async', mock_async_err_handler) monkeypatch.setattr(dp, 'run_async', mock_async_err_handler)
dp.process_update(self.message_update) dp.process_update(self.message_update)
@ -262,17 +256,6 @@ class TestDispatcher:
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
must_raise_runtime_error() must_raise_runtime_error()
def test_run_async_with_args(self, dp):
dp.add_handler(
MessageHandler(
Filters.all, run_async(self.callback_if_not_update_queue), pass_update_queue=True
)
)
dp.update_queue.put(self.message_update)
sleep(0.1)
assert self.received == self.message_update.message
def test_multiple_run_async_deprecation(self, dp): def test_multiple_run_async_deprecation(self, dp):
assert isinstance(dp, Dispatcher) assert isinstance(dp, Dispatcher)
@ -323,8 +306,7 @@ class TestDispatcher:
dp.add_handler( dp.add_handler(
MessageHandler( MessageHandler(
Filters.all, Filters.all,
self.callback_if_not_update_queue, self.callback_received,
pass_update_queue=True,
run_async=True, run_async=True,
) )
) )
@ -343,19 +325,11 @@ class TestDispatcher:
assert len(caplog.records) == 1 assert len(caplog.records) == 1
assert caplog.records[-1].getMessage().startswith('No error handlers are registered') assert caplog.records[-1].getMessage().startswith('No error handlers are registered')
def test_async_handler_error_handler(self, dp): def test_async_handler_async_error_handler_context(self, dp):
dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error, run_async=True)) dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error, run_async=True))
dp.add_error_handler(self.error_handler) dp.add_error_handler(self.error_handler_context, run_async=True)
dp.update_queue.put(self.message_update) dp.update_queue.put(self.message_update)
sleep(0.1)
assert self.received == self.message_update.message.text
def test_async_handler_async_error_handler_context(self, cdp):
cdp.add_handler(MessageHandler(Filters.all, self.callback_raise_error, run_async=True))
cdp.add_error_handler(self.error_handler_context, run_async=True)
cdp.update_queue.put(self.message_update)
sleep(2) sleep(2)
assert self.received == self.message_update.message.text assert self.received == self.message_update.message.text
@ -397,7 +371,7 @@ class TestDispatcher:
def test_error_in_handler(self, dp): def test_error_in_handler(self, dp):
dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error)) dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error))
dp.add_error_handler(self.error_handler) dp.add_error_handler(self.error_handler_context)
dp.update_queue.put(self.message_update) dp.update_queue.put(self.message_update)
sleep(0.1) sleep(0.1)
@ -494,19 +468,19 @@ class TestDispatcher:
passed = [] passed = []
err = Exception('General exception') err = Exception('General exception')
def start1(b, u): def start1(u, c):
passed.append('start1') passed.append('start1')
raise err raise err
def start2(b, u): def start2(u, c):
passed.append('start2') passed.append('start2')
def start3(b, u): def start3(u, c):
passed.append('start3') passed.append('start3')
def error(b, u, e): def error(u, c):
passed.append('error') passed.append('error')
passed.append(e) passed.append(c.error)
update = Update( update = Update(
1, 1,
@ -537,19 +511,19 @@ class TestDispatcher:
passed = [] passed = []
err = TelegramError('Telegram error') err = TelegramError('Telegram error')
def start1(b, u): def start1(u, c):
passed.append('start1') passed.append('start1')
raise err raise err
def start2(b, u): def start2(u, c):
passed.append('start2') passed.append('start2')
def start3(b, u): def start3(u, c):
passed.append('start3') passed.append('start3')
def error(b, u, e): def error(u, c):
passed.append('error') passed.append('error')
passed.append(e) passed.append(c.error)
update = Update( update = Update(
1, 1,
@ -622,10 +596,10 @@ class TestDispatcher:
def flush(self): def flush(self):
pass pass
def start1(b, u): def start1(u, c):
pass pass
def error(b, u, e): def error(u, c):
increment.append("error") increment.append("error")
# If updating a user_data or chat_data from a persistence object throws an error, # If updating a user_data or chat_data from a persistence object throws an error,
@ -646,7 +620,7 @@ class TestDispatcher:
), ),
) )
my_persistence = OwnPersistence() my_persistence = OwnPersistence()
dp = Dispatcher(bot, None, persistence=my_persistence, use_context=False) dp = Dispatcher(bot, None, persistence=my_persistence)
dp.add_handler(CommandHandler('start', start1)) dp.add_handler(CommandHandler('start', start1))
dp.add_error_handler(error) dp.add_error_handler(error)
dp.process_update(update) dp.process_update(update)
@ -656,19 +630,19 @@ class TestDispatcher:
passed = [] passed = []
err = TelegramError('Telegram error') err = TelegramError('Telegram error')
def start1(b, u): def start1(u, c):
passed.append('start1') passed.append('start1')
raise err raise err
def start2(b, u): def start2(u, c):
passed.append('start2') passed.append('start2')
def start3(b, u): def start3(u, c):
passed.append('start3') passed.append('start3')
def error(b, u, e): def error(u, c):
passed.append('error') passed.append('error')
passed.append(e) passed.append(c.error)
raise DispatcherHandlerStop raise DispatcherHandlerStop
update = Update( update = Update(
@ -696,26 +670,12 @@ class TestDispatcher:
assert passed == ['start1', 'error', err] assert passed == ['start1', 'error', err]
assert passed[2] is err assert passed[2] is err
def test_error_handler_context(self, cdp):
cdp.add_error_handler(self.callback_context)
error = TelegramError('Unauthorized.')
cdp.update_queue.put(error)
sleep(0.1)
assert self.received == 'Unauthorized.'
def test_sensible_worker_thread_names(self, dp2): def test_sensible_worker_thread_names(self, dp2):
thread_names = [thread.name for thread in dp2._Dispatcher__async_threads] thread_names = [thread.name for thread in dp2._Dispatcher__async_threads]
for thread_name in thread_names: for thread_name in thread_names:
assert thread_name.startswith(f"Bot:{dp2.bot.id}:worker:") assert thread_name.startswith(f"Bot:{dp2.bot.id}:worker:")
def test_non_context_deprecation(self, dp): def test_error_while_persisting(self, dp, monkeypatch):
with pytest.warns(TelegramDeprecationWarning):
Dispatcher(
dp.bot, dp.update_queue, job_queue=dp.job_queue, workers=0, use_context=False
)
def test_error_while_persisting(self, cdp, monkeypatch):
class OwnPersistence(BasePersistence): class OwnPersistence(BasePersistence):
def update(self, data): def update(self, data):
raise Exception('PersistenceError') raise Exception('PersistenceError')
@ -779,15 +739,15 @@ class TestDispatcher:
1, message=Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text') 1, message=Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')
) )
handler = MessageHandler(Filters.all, callback) handler = MessageHandler(Filters.all, callback)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.add_error_handler(error) dp.add_error_handler(error)
monkeypatch.setattr(cdp.logger, 'exception', logger) monkeypatch.setattr(dp.logger, 'exception', logger)
cdp.persistence = OwnPersistence() dp.persistence = OwnPersistence()
cdp.process_update(update) dp.process_update(update)
assert test_flag assert test_flag
def test_persisting_no_user_no_chat(self, cdp): def test_persisting_no_user_no_chat(self, dp):
class OwnPersistence(BasePersistence): class OwnPersistence(BasePersistence):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -841,25 +801,25 @@ class TestDispatcher:
pass pass
handler = MessageHandler(Filters.all, callback) handler = MessageHandler(Filters.all, callback)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.persistence = OwnPersistence() dp.persistence = OwnPersistence()
update = Update( update = Update(
1, message=Message(1, None, None, from_user=User(1, '', False), text='Text') 1, message=Message(1, None, None, from_user=User(1, '', False), text='Text')
) )
cdp.process_update(update) dp.process_update(update)
assert cdp.persistence.test_flag_bot_data assert dp.persistence.test_flag_bot_data
assert cdp.persistence.test_flag_user_data assert dp.persistence.test_flag_user_data
assert not cdp.persistence.test_flag_chat_data assert not dp.persistence.test_flag_chat_data
cdp.persistence.test_flag_bot_data = False dp.persistence.test_flag_bot_data = False
cdp.persistence.test_flag_user_data = False dp.persistence.test_flag_user_data = False
cdp.persistence.test_flag_chat_data = False dp.persistence.test_flag_chat_data = False
update = Update(1, message=Message(1, None, Chat(1, ''), from_user=None, text='Text')) update = Update(1, message=Message(1, None, Chat(1, ''), from_user=None, text='Text'))
cdp.process_update(update) dp.process_update(update)
assert cdp.persistence.test_flag_bot_data assert dp.persistence.test_flag_bot_data
assert not cdp.persistence.test_flag_user_data assert not dp.persistence.test_flag_user_data
assert cdp.persistence.test_flag_chat_data assert dp.persistence.test_flag_chat_data
def test_update_persistence_once_per_update(self, monkeypatch, dp): def test_update_persistence_once_per_update(self, monkeypatch, dp):
def update_persistence(*args, **kwargs): def update_persistence(*args, **kwargs):

View file

@ -94,29 +94,6 @@ class TestInlineQueryHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_group(self, bot, update, groups=None, groupdict=None):
if groups is not None:
self.test_flag = groups == ('t', ' query')
if groupdict is not None:
self.test_flag = groupdict == {'begin': 't', 'end': ' query'}
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -136,130 +113,44 @@ class TestInlineQueryHandler:
if context.matches[0].groupdict(): if context.matches[0].groupdict():
self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' query'} self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' query'}
def test_basic(self, dp, inline_query):
handler = InlineQueryHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(inline_query)
dp.process_update(inline_query)
assert self.test_flag
def test_with_pattern(self, inline_query):
handler = InlineQueryHandler(self.callback_basic, pattern='(?P<begin>.*)est(?P<end>.*)')
assert handler.check_update(inline_query)
inline_query.inline_query.query = 'nothing here'
assert not handler.check_update(inline_query)
def test_with_passing_group_dict(self, dp, inline_query):
handler = InlineQueryHandler(
self.callback_group, pattern='(?P<begin>.*)est(?P<end>.*)', pass_groups=True
)
dp.add_handler(handler)
dp.process_update(inline_query)
assert self.test_flag
dp.remove_handler(handler)
handler = InlineQueryHandler(
self.callback_group, pattern='(?P<begin>.*)est(?P<end>.*)', pass_groupdict=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(inline_query)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, inline_query):
handler = InlineQueryHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(inline_query)
assert self.test_flag
dp.remove_handler(handler)
handler = InlineQueryHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(inline_query)
assert self.test_flag
dp.remove_handler(handler)
handler = InlineQueryHandler(
self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(inline_query)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, inline_query):
handler = InlineQueryHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(inline_query)
assert self.test_flag
dp.remove_handler(handler)
handler = InlineQueryHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(inline_query)
assert self.test_flag
dp.remove_handler(handler)
handler = InlineQueryHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(inline_query)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = InlineQueryHandler(self.callback_basic) handler = InlineQueryHandler(self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, inline_query): def test_context(self, dp, inline_query):
handler = InlineQueryHandler(self.callback_context) handler = InlineQueryHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(inline_query) dp.process_update(inline_query)
assert self.test_flag assert self.test_flag
def test_context_pattern(self, cdp, inline_query): def test_context_pattern(self, dp, inline_query):
handler = InlineQueryHandler( handler = InlineQueryHandler(
self.callback_context_pattern, pattern=r'(?P<begin>.*)est(?P<end>.*)' self.callback_context_pattern, pattern=r'(?P<begin>.*)est(?P<end>.*)'
) )
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(inline_query) dp.process_update(inline_query)
assert self.test_flag assert self.test_flag
cdp.remove_handler(handler) dp.remove_handler(handler)
handler = InlineQueryHandler(self.callback_context_pattern, pattern=r'(t)est(.*)') handler = InlineQueryHandler(self.callback_context_pattern, pattern=r'(t)est(.*)')
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(inline_query) dp.process_update(inline_query)
assert self.test_flag assert self.test_flag
@pytest.mark.parametrize('chat_types', [[Chat.SENDER], [Chat.SENDER, Chat.SUPERGROUP], []]) @pytest.mark.parametrize('chat_types', [[Chat.SENDER], [Chat.SENDER, Chat.SUPERGROUP], []])
@pytest.mark.parametrize( @pytest.mark.parametrize(
'chat_type,result', [(Chat.SENDER, True), (Chat.CHANNEL, False), (None, False)] 'chat_type,result', [(Chat.SENDER, True), (Chat.CHANNEL, False), (None, False)]
) )
def test_chat_types(self, cdp, inline_query, chat_types, chat_type, result): def test_chat_types(self, dp, inline_query, chat_types, chat_type, result):
try: try:
inline_query.inline_query.chat_type = chat_type inline_query.inline_query.chat_type = chat_type
handler = InlineQueryHandler(self.callback_context, chat_types=chat_types) handler = InlineQueryHandler(self.callback_context, chat_types=chat_types)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(inline_query) dp.process_update(inline_query)
if not chat_types: if not chat_types:
assert self.test_flag is False assert self.test_flag is False

View file

@ -66,20 +66,20 @@ class TestJobQueue:
self.job_time = 0 self.job_time = 0
self.received_error = None self.received_error = None
def job_run_once(self, bot, job): def job_run_once(self, context):
self.result += 1 self.result += 1
def job_with_exception(self, bot, job=None): def job_with_exception(self, context):
raise Exception('Test Error') raise Exception('Test Error')
def job_remove_self(self, bot, job): def job_remove_self(self, context):
self.result += 1 self.result += 1
job.schedule_removal() context.job.schedule_removal()
def job_run_once_with_context(self, bot, job): def job_run_once_with_context(self, context):
self.result += job.context self.result += context.job.context
def job_datetime_tests(self, bot, job): def job_datetime_tests(self, context):
self.job_time = time.time() self.job_time = time.time()
def job_context_based_callback(self, context): def job_context_based_callback(self, context):
@ -95,9 +95,6 @@ class TestJobQueue:
): ):
self.result += 1 self.result += 1
def error_handler(self, bot, update, error):
self.received_error = str(error)
def error_handler_context(self, update, context): def error_handler_context(self, update, context):
self.received_error = str(context.error) self.received_error = str(context.error)
@ -233,7 +230,7 @@ class TestJobQueue:
assert self.result == 1 assert self.result == 1
def test_in_updater(self, bot): def test_in_updater(self, bot):
u = Updater(bot=bot, use_context=False) u = Updater(bot=bot)
u.job_queue.start() u.job_queue.start()
try: try:
u.job_queue.run_repeating(self.job_run_once, 0.02) u.job_queue.run_repeating(self.job_run_once, 0.02)
@ -377,13 +374,8 @@ class TestJobQueue:
finally: finally:
_dp.bot = original_bot _dp.bot = original_bot
@pytest.mark.parametrize('use_context', [True, False]) def test_get_jobs(self, job_queue):
def test_get_jobs(self, job_queue, use_context):
job_queue._dispatcher.use_context = use_context
if use_context:
callback = self.job_context_based_callback callback = self.job_context_based_callback
else:
callback = self.job_run_once
job1 = job_queue.run_once(callback, 10, name='name1') job1 = job_queue.run_once(callback, 10, name='name1')
job2 = job_queue.run_once(callback, 10, name='name1') job2 = job_queue.run_once(callback, 10, name='name1')
@ -393,24 +385,10 @@ class TestJobQueue:
assert job_queue.get_jobs_by_name('name1') == (job1, job2) assert job_queue.get_jobs_by_name('name1') == (job1, job2)
assert job_queue.get_jobs_by_name('name2') == (job3,) assert job_queue.get_jobs_by_name('name2') == (job3,)
def test_context_based_callback(self, job_queue): def test_job_run(self, _dp):
job_queue._dispatcher.use_context = True
job_queue.run_once(self.job_context_based_callback, 0.01, context=2)
sleep(0.03)
assert self.result == 1
job_queue._dispatcher.use_context = False
@pytest.mark.parametrize('use_context', [True, False])
def test_job_run(self, _dp, use_context):
_dp.use_context = use_context
job_queue = JobQueue() job_queue = JobQueue()
job_queue.set_dispatcher(_dp) job_queue.set_dispatcher(_dp)
if use_context:
job = job_queue.run_repeating(self.job_context_based_callback, 0.02, context=2) job = job_queue.run_repeating(self.job_context_based_callback, 0.02, context=2)
else:
job = job_queue.run_repeating(self.job_run_once, 0.02, context=2)
assert self.result == 0 assert self.result == 0
job.run(_dp) job.run(_dp)
assert self.result == 1 assert self.result == 1
@ -443,8 +421,8 @@ class TestJobQueue:
assert not job == job_queue assert not job == job_queue
assert not job < job assert not job < job
def test_dispatch_error(self, job_queue, dp): def test_dispatch_error_context(self, job_queue, dp):
dp.add_error_handler(self.error_handler) dp.add_error_handler(self.error_handler_context)
job = job_queue.run_once(self.job_with_exception, 0.05) job = job_queue.run_once(self.job_with_exception, 0.05)
sleep(0.1) sleep(0.1)
@ -454,7 +432,7 @@ class TestJobQueue:
assert self.received_error == 'Test Error' assert self.received_error == 'Test Error'
# Remove handler # Remove handler
dp.remove_error_handler(self.error_handler) dp.remove_error_handler(self.error_handler_context)
self.received_error = None self.received_error = None
job = job_queue.run_once(self.job_with_exception, 0.05) job = job_queue.run_once(self.job_with_exception, 0.05)
@ -463,26 +441,6 @@ class TestJobQueue:
job.run(dp) job.run(dp)
assert self.received_error is None assert self.received_error is None
def test_dispatch_error_context(self, job_queue, cdp):
cdp.add_error_handler(self.error_handler_context)
job = job_queue.run_once(self.job_with_exception, 0.05)
sleep(0.1)
assert self.received_error == 'Test Error'
self.received_error = None
job.run(cdp)
assert self.received_error == 'Test Error'
# Remove handler
cdp.remove_error_handler(self.error_handler_context)
self.received_error = None
job = job_queue.run_once(self.job_with_exception, 0.05)
sleep(0.1)
assert self.received_error is None
job.run(cdp)
assert self.received_error is None
def test_dispatch_error_that_raises_errors(self, job_queue, dp, caplog): def test_dispatch_error_that_raises_errors(self, job_queue, dp, caplog):
dp.add_error_handler(self.error_handler_raise_error) dp.add_error_handler(self.error_handler_raise_error)

View file

@ -20,7 +20,6 @@ import re
from queue import Queue from queue import Queue
import pytest import pytest
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram import ( from telegram import (
Message, Message,
@ -72,7 +71,7 @@ class TestMessageHandler:
SRE_TYPE = type(re.match("", "")) SRE_TYPE = type(re.match("", ""))
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
handler = MessageHandler(Filters.all, self.callback_basic) handler = MessageHandler(Filters.all, self.callback_context)
for attr in handler.__slots__: for attr in handler.__slots__:
assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot" assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
@ -81,23 +80,6 @@ class TestMessageHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -137,75 +119,8 @@ class TestMessageHandler:
num = len(context.matches) == 2 num = len(context.matches) == 2
self.test_flag = types and num self.test_flag = types and num
def test_basic(self, dp, message):
handler = MessageHandler(None, self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(Update(0, message))
dp.process_update(Update(0, message))
assert self.test_flag
def test_deprecation_warning(self):
with pytest.warns(TelegramDeprecationWarning, match='See https://git.io/fxJuV'):
MessageHandler(None, self.callback_basic, edited_updates=True)
with pytest.warns(TelegramDeprecationWarning, match='See https://git.io/fxJuV'):
MessageHandler(None, self.callback_basic, message_updates=False)
with pytest.warns(TelegramDeprecationWarning, match='See https://git.io/fxJuV'):
MessageHandler(None, self.callback_basic, channel_post_updates=True)
def test_edited_deprecated(self, message):
handler = MessageHandler(
None,
self.callback_basic,
edited_updates=True,
message_updates=False,
channel_post_updates=False,
)
assert handler.check_update(Update(0, edited_message=message))
assert not handler.check_update(Update(0, message=message))
assert not handler.check_update(Update(0, channel_post=message))
assert handler.check_update(Update(0, edited_channel_post=message))
def test_channel_post_deprecated(self, message):
handler = MessageHandler(
None,
self.callback_basic,
edited_updates=False,
message_updates=False,
channel_post_updates=True,
)
assert not handler.check_update(Update(0, edited_message=message))
assert not handler.check_update(Update(0, message=message))
assert handler.check_update(Update(0, channel_post=message))
assert not handler.check_update(Update(0, edited_channel_post=message))
def test_multiple_flags_deprecated(self, message):
handler = MessageHandler(
None,
self.callback_basic,
edited_updates=True,
message_updates=True,
channel_post_updates=True,
)
assert handler.check_update(Update(0, edited_message=message))
assert handler.check_update(Update(0, message=message))
assert handler.check_update(Update(0, channel_post=message))
assert handler.check_update(Update(0, edited_channel_post=message))
def test_none_allowed_deprecated(self):
with pytest.raises(ValueError, match='are all False'):
MessageHandler(
None,
self.callback_basic,
message_updates=False,
channel_post_updates=False,
edited_updates=False,
)
def test_with_filter(self, message): def test_with_filter(self, message):
handler = MessageHandler(Filters.group, self.callback_basic) handler = MessageHandler(Filters.group, self.callback_context)
message.chat.type = 'group' message.chat.type = 'group'
assert handler.check_update(Update(0, message)) assert handler.check_update(Update(0, message))
@ -221,7 +136,7 @@ class TestMessageHandler:
self.flag = True self.flag = True
test_filter = TestFilter() test_filter = TestFilter()
handler = MessageHandler(test_filter, self.callback_basic) handler = MessageHandler(test_filter, self.callback_context)
update = Update(1, callback_query=CallbackQuery(1, None, None, message=message)) update = Update(1, callback_query=CallbackQuery(1, None, None, message=message))
@ -235,110 +150,61 @@ class TestMessageHandler:
& ~Filters.update.channel_post & ~Filters.update.channel_post
& Filters.update.edited_channel_post & Filters.update.edited_channel_post
) )
handler = MessageHandler(f, self.callback_basic) handler = MessageHandler(f, self.callback_context)
assert not handler.check_update(Update(0, edited_message=message)) assert not handler.check_update(Update(0, edited_message=message))
assert not handler.check_update(Update(0, message=message)) assert not handler.check_update(Update(0, message=message))
assert not handler.check_update(Update(0, channel_post=message)) assert not handler.check_update(Update(0, channel_post=message))
assert handler.check_update(Update(0, edited_channel_post=message)) assert handler.check_update(Update(0, edited_channel_post=message))
def test_pass_user_or_chat_data(self, dp, message):
handler = MessageHandler(None, self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = MessageHandler(None, self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = MessageHandler(
None, self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, message):
handler = MessageHandler(None, self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = MessageHandler(None, self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = MessageHandler(
None, self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = MessageHandler(None, self.callback_basic, edited_updates=True) handler = MessageHandler(None, self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, message): def test_context(self, dp, message):
handler = MessageHandler( handler = MessageHandler(
None, self.callback_context, edited_updates=True, channel_post_updates=True None,
self.callback_context,
) )
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(Update(0, message=message)) dp.process_update(Update(0, message=message))
assert self.test_flag assert self.test_flag
self.test_flag = False self.test_flag = False
cdp.process_update(Update(0, edited_message=message)) dp.process_update(Update(0, edited_message=message))
assert self.test_flag assert self.test_flag
self.test_flag = False self.test_flag = False
cdp.process_update(Update(0, channel_post=message)) dp.process_update(Update(0, channel_post=message))
assert self.test_flag assert self.test_flag
self.test_flag = False self.test_flag = False
cdp.process_update(Update(0, edited_channel_post=message)) dp.process_update(Update(0, edited_channel_post=message))
assert self.test_flag assert self.test_flag
def test_context_regex(self, cdp, message): def test_context_regex(self, dp, message):
handler = MessageHandler(Filters.regex('one two'), self.callback_context_regex1) handler = MessageHandler(Filters.regex('one two'), self.callback_context_regex1)
cdp.add_handler(handler) dp.add_handler(handler)
message.text = 'not it' message.text = 'not it'
cdp.process_update(Update(0, message)) dp.process_update(Update(0, message))
assert not self.test_flag assert not self.test_flag
message.text += ' one two now it is' message.text += ' one two now it is'
cdp.process_update(Update(0, message)) dp.process_update(Update(0, message))
assert self.test_flag assert self.test_flag
def test_context_multiple_regex(self, cdp, message): def test_context_multiple_regex(self, dp, message):
handler = MessageHandler( handler = MessageHandler(
Filters.regex('one') & Filters.regex('two'), self.callback_context_regex2 Filters.regex('one') & Filters.regex('two'), self.callback_context_regex2
) )
cdp.add_handler(handler) dp.add_handler(handler)
message.text = 'not it' message.text = 'not it'
cdp.process_update(Update(0, message)) dp.process_update(Update(0, message))
assert not self.test_flag assert not self.test_flag
message.text += ' one two now it is' message.text += ' one two now it is'
cdp.process_update(Update(0, message)) dp.process_update(Update(0, message))
assert self.test_flag assert self.test_flag

View file

@ -342,7 +342,7 @@ class TestBasePersistence:
@pytest.mark.parametrize('run_async', [True, False], ids=['synchronous', 'run_async']) @pytest.mark.parametrize('run_async', [True, False], ids=['synchronous', 'run_async'])
def test_dispatcher_integration_handlers( def test_dispatcher_integration_handlers(
self, self,
cdp, dp,
caplog, caplog,
bot, bot,
base_persistence, base_persistence,
@ -373,7 +373,7 @@ class TestBasePersistence:
base_persistence.refresh_bot_data = lambda x: x base_persistence.refresh_bot_data = lambda x: x
base_persistence.refresh_chat_data = lambda x, y: x base_persistence.refresh_chat_data = lambda x, y: x
base_persistence.refresh_user_data = lambda x, y: x base_persistence.refresh_user_data = lambda x, y: x
updater = Updater(bot=bot, persistence=base_persistence, use_context=True) updater = Updater(bot=bot, persistence=base_persistence)
dp = updater.dispatcher dp = updater.dispatcher
def callback_known_user(update, context): def callback_known_user(update, context):
@ -403,17 +403,14 @@ class TestBasePersistence:
known_user = MessageHandler( known_user = MessageHandler(
Filters.user(user_id=12345), Filters.user(user_id=12345),
callback_known_user, callback_known_user,
pass_chat_data=True,
pass_user_data=True,
) )
known_chat = MessageHandler( known_chat = MessageHandler(
Filters.chat(chat_id=-67890), Filters.chat(chat_id=-67890),
callback_known_chat, callback_known_chat,
pass_chat_data=True,
pass_user_data=True,
) )
unknown = MessageHandler( unknown = MessageHandler(
Filters.all, callback_unknown_user_or_chat, pass_chat_data=True, pass_user_data=True Filters.all,
callback_unknown_user_or_chat,
) )
dp.add_handler(known_user) dp.add_handler(known_user)
dp.add_handler(known_chat) dp.add_handler(known_chat)
@ -481,7 +478,7 @@ class TestBasePersistence:
@pytest.mark.parametrize('run_async', [True, False], ids=['synchronous', 'run_async']) @pytest.mark.parametrize('run_async', [True, False], ids=['synchronous', 'run_async'])
def test_persistence_dispatcher_integration_refresh_data( def test_persistence_dispatcher_integration_refresh_data(
self, self,
cdp, dp,
base_persistence, base_persistence,
chat_data, chat_data,
bot_data, bot_data,
@ -500,7 +497,7 @@ class TestBasePersistence:
base_persistence.store_data = PersistenceInput( base_persistence.store_data = PersistenceInput(
bot_data=store_bot_data, chat_data=store_chat_data, user_data=store_user_data bot_data=store_bot_data, chat_data=store_chat_data, user_data=store_user_data
) )
cdp.persistence = base_persistence dp.persistence = base_persistence
self.test_flag = True self.test_flag = True
@ -535,26 +532,22 @@ class TestBasePersistence:
with_user_and_chat = MessageHandler( with_user_and_chat = MessageHandler(
Filters.user(user_id=12345), Filters.user(user_id=12345),
callback_with_user_and_chat, callback_with_user_and_chat,
pass_chat_data=True,
pass_user_data=True,
run_async=run_async, run_async=run_async,
) )
without_user_and_chat = MessageHandler( without_user_and_chat = MessageHandler(
Filters.all, Filters.all,
callback_without_user_and_chat, callback_without_user_and_chat,
pass_chat_data=True,
pass_user_data=True,
run_async=run_async, run_async=run_async,
) )
cdp.add_handler(with_user_and_chat) dp.add_handler(with_user_and_chat)
cdp.add_handler(without_user_and_chat) dp.add_handler(without_user_and_chat)
user = User(id=12345, first_name='test user', is_bot=False) user = User(id=12345, first_name='test user', is_bot=False)
chat = Chat(id=-987654, type='group') chat = Chat(id=-987654, type='group')
m = Message(1, None, chat, from_user=user) m = Message(1, None, chat, from_user=user)
# has user and chat # has user and chat
u = Update(0, m) u = Update(0, m)
cdp.process_update(u) dp.process_update(u)
assert self.test_flag is True assert self.test_flag is True
@ -562,7 +555,7 @@ class TestBasePersistence:
m.from_user = None m.from_user = None
m.chat = None m.chat = None
u = Update(1, m) u = Update(1, m)
cdp.process_update(u) dp.process_update(u)
assert self.test_flag is True assert self.test_flag is True
@ -1630,7 +1623,7 @@ class TestPicklePersistence:
assert conversations_test['name1'] == conversation1 assert conversations_test['name1'] == conversation1
def test_with_handler(self, bot, update, bot_data, pickle_persistence, good_pickle_files): def test_with_handler(self, bot, update, bot_data, pickle_persistence, good_pickle_files):
u = Updater(bot=bot, persistence=pickle_persistence, use_context=True) u = Updater(bot=bot, persistence=pickle_persistence)
dp = u.dispatcher dp = u.dispatcher
bot.callback_data_cache.clear_callback_data() bot.callback_data_cache.clear_callback_data()
bot.callback_data_cache.clear_callback_queries() bot.callback_data_cache.clear_callback_queries()
@ -1659,8 +1652,8 @@ class TestPicklePersistence:
if not context.bot.callback_data_cache.persistence_data == ([], {'test1': 'test0'}): if not context.bot.callback_data_cache.persistence_data == ([], {'test1': 'test0'}):
pytest.fail() pytest.fail()
h1 = MessageHandler(None, first, pass_user_data=True, pass_chat_data=True) h1 = MessageHandler(None, first)
h2 = MessageHandler(None, second, pass_user_data=True, pass_chat_data=True) h2 = MessageHandler(None, second)
dp.add_handler(h1) dp.add_handler(h1)
dp.process_update(update) dp.process_update(update)
pickle_persistence_2 = PicklePersistence( pickle_persistence_2 = PicklePersistence(
@ -1779,7 +1772,6 @@ class TestPicklePersistence:
def test_with_conversation_handler(self, dp, update, good_pickle_files, pickle_persistence): def test_with_conversation_handler(self, dp, update, good_pickle_files, pickle_persistence):
dp.persistence = pickle_persistence dp.persistence = pickle_persistence
dp.use_context = True
NEXT, NEXT2 = range(2) NEXT, NEXT2 = range(2)
def start(update, context): def start(update, context):
@ -1814,7 +1806,6 @@ class TestPicklePersistence:
self, dp, update, good_pickle_files, pickle_persistence self, dp, update, good_pickle_files, pickle_persistence
): ):
dp.persistence = pickle_persistence dp.persistence = pickle_persistence
dp.use_context = True
NEXT2, NEXT3 = range(1, 3) NEXT2, NEXT3 = range(1, 3)
def start(update, context): def start(update, context):
@ -1862,8 +1853,8 @@ class TestPicklePersistence:
assert nested_ch.conversations[nested_ch._get_key(update)] == 1 assert nested_ch.conversations[nested_ch._get_key(update)] == 1
assert nested_ch.conversations == pickle_persistence.conversations['name3'] assert nested_ch.conversations == pickle_persistence.conversations['name3']
def test_with_job(self, job_queue, cdp, pickle_persistence): def test_with_job(self, job_queue, dp, pickle_persistence):
cdp.bot.arbitrary_callback_data = True dp.bot.arbitrary_callback_data = True
def job_callback(context): def job_callback(context):
context.bot_data['test1'] = '456' context.bot_data['test1'] = '456'
@ -1871,8 +1862,8 @@ class TestPicklePersistence:
context.dispatcher.user_data[789]['test3'] = '123' context.dispatcher.user_data[789]['test3'] = '123'
context.bot.callback_data_cache._callback_queries['test'] = 'Working4!' context.bot.callback_data_cache._callback_queries['test'] = 'Working4!'
cdp.persistence = pickle_persistence dp.persistence = pickle_persistence
job_queue.set_dispatcher(cdp) job_queue.set_dispatcher(dp)
job_queue.start() job_queue.start()
job_queue.run_once(job_callback, 0.01) job_queue.run_once(job_callback, 0.01)
sleep(0.5) sleep(0.5)
@ -2185,7 +2176,7 @@ class TestDictPersistence:
def test_with_handler(self, bot, update): def test_with_handler(self, bot, update):
dict_persistence = DictPersistence() dict_persistence = DictPersistence()
u = Updater(bot=bot, persistence=dict_persistence, use_context=True) u = Updater(bot=bot, persistence=dict_persistence)
dp = u.dispatcher dp = u.dispatcher
def first(update, context): def first(update, context):
@ -2235,7 +2226,6 @@ class TestDictPersistence:
def test_with_conversationHandler(self, dp, update, conversations_json): def test_with_conversationHandler(self, dp, update, conversations_json):
dict_persistence = DictPersistence(conversations_json=conversations_json) dict_persistence = DictPersistence(conversations_json=conversations_json)
dp.persistence = dict_persistence dp.persistence = dict_persistence
dp.use_context = True
NEXT, NEXT2 = range(2) NEXT, NEXT2 = range(2)
def start(update, context): def start(update, context):
@ -2269,7 +2259,6 @@ class TestDictPersistence:
def test_with_nested_conversationHandler(self, dp, update, conversations_json): def test_with_nested_conversationHandler(self, dp, update, conversations_json):
dict_persistence = DictPersistence(conversations_json=conversations_json) dict_persistence = DictPersistence(conversations_json=conversations_json)
dp.persistence = dict_persistence dp.persistence = dict_persistence
dp.use_context = True
NEXT2, NEXT3 = range(1, 3) NEXT2, NEXT3 = range(1, 3)
def start(update, context): def start(update, context):
@ -2317,8 +2306,8 @@ class TestDictPersistence:
assert nested_ch.conversations[nested_ch._get_key(update)] == 1 assert nested_ch.conversations[nested_ch._get_key(update)] == 1
assert nested_ch.conversations == dict_persistence.conversations['name3'] assert nested_ch.conversations == dict_persistence.conversations['name3']
def test_with_job(self, job_queue, cdp): def test_with_job(self, job_queue, dp):
cdp.bot.arbitrary_callback_data = True dp.bot.arbitrary_callback_data = True
def job_callback(context): def job_callback(context):
context.bot_data['test1'] = '456' context.bot_data['test1'] = '456'
@ -2327,8 +2316,8 @@ class TestDictPersistence:
context.bot.callback_data_cache._callback_queries['test'] = 'Working4!' context.bot.callback_data_cache._callback_queries['test'] = 'Working4!'
dict_persistence = DictPersistence() dict_persistence = DictPersistence()
cdp.persistence = dict_persistence dp.persistence = dict_persistence
job_queue.set_dispatcher(cdp) job_queue.set_dispatcher(dp)
job_queue.start() job_queue.start()
job_queue.run_once(job_callback, 0.01) job_queue.run_once(job_callback, 0.01)
sleep(0.8) sleep(0.8)

View file

@ -75,7 +75,7 @@ class TestPollAnswerHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
handler = PollAnswerHandler(self.callback_basic) handler = PollAnswerHandler(self.callback_context)
for attr in handler.__slots__: for attr in handler.__slots__:
assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot" assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
@ -84,23 +84,6 @@ class TestPollAnswerHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -114,70 +97,13 @@ class TestPollAnswerHandler:
and isinstance(update.poll_answer, PollAnswer) and isinstance(update.poll_answer, PollAnswer)
) )
def test_basic(self, dp, poll_answer):
handler = PollAnswerHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(poll_answer)
dp.process_update(poll_answer)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, poll_answer):
handler = PollAnswerHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(poll_answer)
assert self.test_flag
dp.remove_handler(handler)
handler = PollAnswerHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll_answer)
assert self.test_flag
dp.remove_handler(handler)
handler = PollAnswerHandler(self.callback_data_2, pass_chat_data=True, pass_user_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll_answer)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, poll_answer):
handler = PollAnswerHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(poll_answer)
assert self.test_flag
dp.remove_handler(handler)
handler = PollAnswerHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll_answer)
assert self.test_flag
dp.remove_handler(handler)
handler = PollAnswerHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll_answer)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = PollAnswerHandler(self.callback_basic) handler = PollAnswerHandler(self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, poll_answer): def test_context(self, dp, poll_answer):
handler = PollAnswerHandler(self.callback_context) handler = PollAnswerHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(poll_answer) dp.process_update(poll_answer)
assert self.test_flag assert self.test_flag

View file

@ -88,7 +88,7 @@ class TestPollHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
inst = PollHandler(self.callback_basic) inst = PollHandler(self.callback_context)
for attr in inst.__slots__: for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
@ -97,23 +97,6 @@ class TestPollHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -127,68 +110,13 @@ class TestPollHandler:
and isinstance(update.poll, Poll) and isinstance(update.poll, Poll)
) )
def test_basic(self, dp, poll):
handler = PollHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(poll)
dp.process_update(poll)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, poll):
handler = PollHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(poll)
assert self.test_flag
dp.remove_handler(handler)
handler = PollHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll)
assert self.test_flag
dp.remove_handler(handler)
handler = PollHandler(self.callback_data_2, pass_chat_data=True, pass_user_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, poll):
handler = PollHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(poll)
assert self.test_flag
dp.remove_handler(handler)
handler = PollHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll)
assert self.test_flag
dp.remove_handler(handler)
handler = PollHandler(self.callback_queue_2, pass_job_queue=True, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(poll)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = PollHandler(self.callback_basic) handler = PollHandler(self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, poll): def test_context(self, dp, poll):
handler = PollHandler(self.callback_context) handler = PollHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(poll) dp.process_update(poll)
assert self.test_flag assert self.test_flag

View file

@ -80,7 +80,7 @@ class TestPreCheckoutQueryHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
inst = PreCheckoutQueryHandler(self.callback_basic) inst = PreCheckoutQueryHandler(self.callback_context)
for attr in inst.__slots__: for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
@ -89,23 +89,6 @@ class TestPreCheckoutQueryHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -119,71 +102,13 @@ class TestPreCheckoutQueryHandler:
and isinstance(update.pre_checkout_query, PreCheckoutQuery) and isinstance(update.pre_checkout_query, PreCheckoutQuery)
) )
def test_basic(self, dp, pre_checkout_query):
handler = PreCheckoutQueryHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(pre_checkout_query)
dp.process_update(pre_checkout_query)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, pre_checkout_query):
handler = PreCheckoutQueryHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(pre_checkout_query)
assert self.test_flag
dp.remove_handler(handler)
handler = PreCheckoutQueryHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(pre_checkout_query)
assert self.test_flag
dp.remove_handler(handler)
handler = PreCheckoutQueryHandler(
self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(pre_checkout_query)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, pre_checkout_query):
handler = PreCheckoutQueryHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(pre_checkout_query)
assert self.test_flag
dp.remove_handler(handler)
handler = PreCheckoutQueryHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(pre_checkout_query)
assert self.test_flag
dp.remove_handler(handler)
handler = PreCheckoutQueryHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(pre_checkout_query)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = PreCheckoutQueryHandler(self.callback_basic) handler = PreCheckoutQueryHandler(self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, pre_checkout_query): def test_context(self, dp, pre_checkout_query):
handler = PreCheckoutQueryHandler(self.callback_context) handler = PreCheckoutQueryHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(pre_checkout_query) dp.process_update(pre_checkout_query)
assert self.test_flag assert self.test_flag

View file

@ -1,289 +0,0 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2022
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
from queue import Queue
import pytest
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram import (
Message,
Update,
Chat,
Bot,
User,
CallbackQuery,
InlineQuery,
ChosenInlineResult,
ShippingQuery,
PreCheckoutQuery,
)
from telegram.ext import RegexHandler, CallbackContext, JobQueue
message = Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')
params = [
{'callback_query': CallbackQuery(1, User(1, '', False), 'chat', message=message)},
{'inline_query': InlineQuery(1, User(1, '', False), '', '')},
{'chosen_inline_result': ChosenInlineResult('id', User(1, '', False), '')},
{'shipping_query': ShippingQuery('id', User(1, '', False), '', None)},
{'pre_checkout_query': PreCheckoutQuery('id', User(1, '', False), '', 0, '')},
{'callback_query': CallbackQuery(1, User(1, '', False), 'chat')},
]
ids = (
'callback_query',
'inline_query',
'chosen_inline_result',
'shipping_query',
'pre_checkout_query',
'callback_query_without_message',
)
@pytest.fixture(scope='class', params=params, ids=ids)
def false_update(request):
return Update(update_id=1, **request.param)
@pytest.fixture(scope='class')
def message(bot):
return Message(
1, None, Chat(1, ''), from_user=User(1, '', False), text='test message', bot=bot
)
class TestRegexHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
inst = RegexHandler("", self.callback_basic)
for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
@pytest.fixture(autouse=True)
def reset(self):
self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_group(self, bot, update, groups=None, groupdict=None):
if groups is not None:
self.test_flag = groups == ('t', ' message')
if groupdict is not None:
self.test_flag = groupdict == {'begin': 't', 'end': ' message'}
def callback_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
and isinstance(context.bot, Bot)
and isinstance(update, Update)
and isinstance(context.update_queue, Queue)
and isinstance(context.job_queue, JobQueue)
and isinstance(context.user_data, dict)
and isinstance(context.chat_data, dict)
and isinstance(context.bot_data, dict)
and isinstance(update.message, Message)
)
def callback_context_pattern(self, update, context):
if context.matches[0].groups():
self.test_flag = context.matches[0].groups() == ('t', ' message')
if context.matches[0].groupdict():
self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' message'}
def test_deprecation_Warning(self):
with pytest.warns(TelegramDeprecationWarning, match='RegexHandler is deprecated.'):
RegexHandler('.*', self.callback_basic)
def test_basic(self, dp, message):
handler = RegexHandler('.*', self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(Update(0, message))
dp.process_update(Update(0, message))
assert self.test_flag
def test_pattern(self, message):
handler = RegexHandler('.*est.*', self.callback_basic)
assert handler.check_update(Update(0, message))
handler = RegexHandler('.*not in here.*', self.callback_basic)
assert not handler.check_update(Update(0, message))
def test_with_passing_group_dict(self, dp, message):
handler = RegexHandler(
'(?P<begin>.*)est(?P<end>.*)', self.callback_group, pass_groups=True
)
dp.add_handler(handler)
dp.process_update(Update(0, message))
assert self.test_flag
dp.remove_handler(handler)
handler = RegexHandler(
'(?P<begin>.*)est(?P<end>.*)', self.callback_group, pass_groupdict=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message))
assert self.test_flag
def test_edited(self, message):
handler = RegexHandler(
'.*',
self.callback_basic,
edited_updates=True,
message_updates=False,
channel_post_updates=False,
)
assert handler.check_update(Update(0, edited_message=message))
assert not handler.check_update(Update(0, message=message))
assert not handler.check_update(Update(0, channel_post=message))
assert handler.check_update(Update(0, edited_channel_post=message))
def test_channel_post(self, message):
handler = RegexHandler(
'.*',
self.callback_basic,
edited_updates=False,
message_updates=False,
channel_post_updates=True,
)
assert not handler.check_update(Update(0, edited_message=message))
assert not handler.check_update(Update(0, message=message))
assert handler.check_update(Update(0, channel_post=message))
assert not handler.check_update(Update(0, edited_channel_post=message))
def test_multiple_flags(self, message):
handler = RegexHandler(
'.*',
self.callback_basic,
edited_updates=True,
message_updates=True,
channel_post_updates=True,
)
assert handler.check_update(Update(0, edited_message=message))
assert handler.check_update(Update(0, message=message))
assert handler.check_update(Update(0, channel_post=message))
assert handler.check_update(Update(0, edited_channel_post=message))
def test_none_allowed(self):
with pytest.raises(ValueError, match='are all False'):
RegexHandler(
'.*',
self.callback_basic,
message_updates=False,
channel_post_updates=False,
edited_updates=False,
)
def test_pass_user_or_chat_data(self, dp, message):
handler = RegexHandler('.*', self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = RegexHandler('.*', self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = RegexHandler(
'.*', self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, message):
handler = RegexHandler('.*', self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = RegexHandler('.*', self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
dp.remove_handler(handler)
handler = RegexHandler(
'.*', self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(Update(0, message=message))
assert self.test_flag
def test_other_update_types(self, false_update):
handler = RegexHandler('.*', self.callback_basic, edited_updates=True)
assert not handler.check_update(false_update)
def test_context(self, cdp, message):
handler = RegexHandler(r'(t)est(.*)', self.callback_context)
cdp.add_handler(handler)
cdp.process_update(Update(0, message=message))
assert self.test_flag
def test_context_pattern(self, cdp, message):
handler = RegexHandler(r'(t)est(.*)', self.callback_context_pattern)
cdp.add_handler(handler)
cdp.process_update(Update(0, message=message))
assert self.test_flag
cdp.remove_handler(handler)
handler = RegexHandler(r'(t)est(.*)', self.callback_context_pattern)
cdp.add_handler(handler)
cdp.process_update(Update(0, message=message))
assert self.test_flag

View file

@ -84,7 +84,7 @@ class TestShippingQueryHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
inst = ShippingQueryHandler(self.callback_basic) inst = ShippingQueryHandler(self.callback_context)
for attr in inst.__slots__: for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
@ -93,23 +93,6 @@ class TestShippingQueryHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
def callback_data_1(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) or (chat_data is not None)
def callback_data_2(self, bot, update, user_data=None, chat_data=None):
self.test_flag = (user_data is not None) and (chat_data is not None)
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -123,71 +106,13 @@ class TestShippingQueryHandler:
and isinstance(update.shipping_query, ShippingQuery) and isinstance(update.shipping_query, ShippingQuery)
) )
def test_basic(self, dp, shiping_query):
handler = ShippingQueryHandler(self.callback_basic)
dp.add_handler(handler)
assert handler.check_update(shiping_query)
dp.process_update(shiping_query)
assert self.test_flag
def test_pass_user_or_chat_data(self, dp, shiping_query):
handler = ShippingQueryHandler(self.callback_data_1, pass_user_data=True)
dp.add_handler(handler)
dp.process_update(shiping_query)
assert self.test_flag
dp.remove_handler(handler)
handler = ShippingQueryHandler(self.callback_data_1, pass_chat_data=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(shiping_query)
assert self.test_flag
dp.remove_handler(handler)
handler = ShippingQueryHandler(
self.callback_data_2, pass_chat_data=True, pass_user_data=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(shiping_query)
assert self.test_flag
def test_pass_job_or_update_queue(self, dp, shiping_query):
handler = ShippingQueryHandler(self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update(shiping_query)
assert self.test_flag
dp.remove_handler(handler)
handler = ShippingQueryHandler(self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(shiping_query)
assert self.test_flag
dp.remove_handler(handler)
handler = ShippingQueryHandler(
self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update(shiping_query)
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = ShippingQueryHandler(self.callback_basic) handler = ShippingQueryHandler(self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp, shiping_query): def test_context(self, dp, shiping_query):
handler = ShippingQueryHandler(self.callback_context) handler = ShippingQueryHandler(self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update(shiping_query) dp.process_update(shiping_query)
assert self.test_flag assert self.test_flag

View file

@ -72,7 +72,7 @@ class TestStringCommandHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
inst = StringCommandHandler('sleepy', self.callback_basic) inst = StringCommandHandler('sleepy', self.callback_context)
for attr in inst.__slots__: for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
@ -81,23 +81,6 @@ class TestStringCommandHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, str)
self.test_flag = test_bot and test_update
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def sch_callback_args(self, bot, update, args):
if update == '/test':
self.test_flag = len(args) == 0
else:
self.test_flag = args == ['one', 'two']
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -113,75 +96,23 @@ class TestStringCommandHandler:
def callback_context_args(self, update, context): def callback_context_args(self, update, context):
self.test_flag = context.args == ['one', 'two'] self.test_flag = context.args == ['one', 'two']
def test_basic(self, dp):
handler = StringCommandHandler('test', self.callback_basic)
dp.add_handler(handler)
check = handler.check_update('/test')
assert check is not None and check is not False
dp.process_update('/test')
assert self.test_flag
check = handler.check_update('/nottest')
assert check is None or check is False
check = handler.check_update('not /test in front')
assert check is None or check is False
check = handler.check_update('/test followed by text')
assert check is not None and check is not False
def test_pass_args(self, dp):
handler = StringCommandHandler('test', self.sch_callback_args, pass_args=True)
dp.add_handler(handler)
dp.process_update('/test')
assert self.test_flag
self.test_flag = False
dp.process_update('/test one two')
assert self.test_flag
def test_pass_job_or_update_queue(self, dp):
handler = StringCommandHandler('test', self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update('/test')
assert self.test_flag
dp.remove_handler(handler)
handler = StringCommandHandler('test', self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update('/test')
assert self.test_flag
dp.remove_handler(handler)
handler = StringCommandHandler(
'test', self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update('/test')
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = StringCommandHandler('test', self.callback_basic) handler = StringCommandHandler('test', self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp): def test_context(self, dp):
handler = StringCommandHandler('test', self.callback_context) handler = StringCommandHandler('test', self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update('/test') dp.process_update('/test')
assert self.test_flag assert self.test_flag
def test_context_args(self, cdp): def test_context_args(self, dp):
handler = StringCommandHandler('test', self.callback_context_args) handler = StringCommandHandler('test', self.callback_context_args)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update('/test') dp.process_update('/test')
assert not self.test_flag assert not self.test_flag
cdp.process_update('/test one two') dp.process_update('/test one two')
assert self.test_flag assert self.test_flag

View file

@ -72,7 +72,7 @@ class TestStringRegexHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
inst = StringRegexHandler('pfft', self.callback_basic) inst = StringRegexHandler('pfft', self.callback_context)
for attr in inst.__slots__: for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
@ -81,23 +81,6 @@ class TestStringRegexHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, str)
self.test_flag = test_bot and test_update
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_group(self, bot, update, groups=None, groupdict=None):
if groups is not None:
self.test_flag = groups == ('t', ' message')
if groupdict is not None:
self.test_flag = groupdict == {'begin': 't', 'end': ' message'}
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -114,7 +97,7 @@ class TestStringRegexHandler:
self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' message'} self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' message'}
def test_basic(self, dp): def test_basic(self, dp):
handler = StringRegexHandler('(?P<begin>.*)est(?P<end>.*)', self.callback_basic) handler = StringRegexHandler('(?P<begin>.*)est(?P<end>.*)', self.callback_context)
dp.add_handler(handler) dp.add_handler(handler)
assert handler.check_update('test message') assert handler.check_update('test message')
@ -123,71 +106,27 @@ class TestStringRegexHandler:
assert not handler.check_update('does not match') assert not handler.check_update('does not match')
def test_with_passing_group_dict(self, dp):
handler = StringRegexHandler(
'(?P<begin>.*)est(?P<end>.*)', self.callback_group, pass_groups=True
)
dp.add_handler(handler)
dp.process_update('test message')
assert self.test_flag
dp.remove_handler(handler)
handler = StringRegexHandler(
'(?P<begin>.*)est(?P<end>.*)', self.callback_group, pass_groupdict=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update('test message')
assert self.test_flag
def test_pass_job_or_update_queue(self, dp):
handler = StringRegexHandler('test', self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update('test')
assert self.test_flag
dp.remove_handler(handler)
handler = StringRegexHandler('test', self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update('test')
assert self.test_flag
dp.remove_handler(handler)
handler = StringRegexHandler(
'test', self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update('test')
assert self.test_flag
def test_other_update_types(self, false_update): def test_other_update_types(self, false_update):
handler = StringRegexHandler('test', self.callback_basic) handler = StringRegexHandler('test', self.callback_context)
assert not handler.check_update(false_update) assert not handler.check_update(false_update)
def test_context(self, cdp): def test_context(self, dp):
handler = StringRegexHandler(r'(t)est(.*)', self.callback_context) handler = StringRegexHandler(r'(t)est(.*)', self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update('test message') dp.process_update('test message')
assert self.test_flag assert self.test_flag
def test_context_pattern(self, cdp): def test_context_pattern(self, dp):
handler = StringRegexHandler(r'(t)est(.*)', self.callback_context_pattern) handler = StringRegexHandler(r'(t)est(.*)', self.callback_context_pattern)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update('test message') dp.process_update('test message')
assert self.test_flag assert self.test_flag
cdp.remove_handler(handler) dp.remove_handler(handler)
handler = StringRegexHandler(r'(t)est(.*)', self.callback_context_pattern) handler = StringRegexHandler(r'(t)est(.*)', self.callback_context_pattern)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update('test message') dp.process_update('test message')
assert self.test_flag assert self.test_flag

View file

@ -29,7 +29,7 @@ class TestTypeHandler:
test_flag = False test_flag = False
def test_slot_behaviour(self, mro_slots): def test_slot_behaviour(self, mro_slots):
inst = TypeHandler(dict, self.callback_basic) inst = TypeHandler(dict, self.callback_context)
for attr in inst.__slots__: for attr in inst.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'" assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot"
@ -38,17 +38,6 @@ class TestTypeHandler:
def reset(self): def reset(self):
self.test_flag = False self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
test_update = isinstance(update, dict)
self.test_flag = test_bot and test_update
def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) or (update_queue is not None)
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
self.test_flag = (job_queue is not None) and (update_queue is not None)
def callback_context(self, update, context): def callback_context(self, update, context):
self.test_flag = ( self.test_flag = (
isinstance(context, CallbackContext) isinstance(context, CallbackContext)
@ -62,7 +51,7 @@ class TestTypeHandler:
) )
def test_basic(self, dp): def test_basic(self, dp):
handler = TypeHandler(dict, self.callback_basic) handler = TypeHandler(dict, self.callback_context)
dp.add_handler(handler) dp.add_handler(handler)
assert handler.check_update({'a': 1, 'b': 2}) assert handler.check_update({'a': 1, 'b': 2})
@ -71,39 +60,14 @@ class TestTypeHandler:
assert self.test_flag assert self.test_flag
def test_strict(self): def test_strict(self):
handler = TypeHandler(dict, self.callback_basic, strict=True) handler = TypeHandler(dict, self.callback_context, strict=True)
o = OrderedDict({'a': 1, 'b': 2}) o = OrderedDict({'a': 1, 'b': 2})
assert handler.check_update({'a': 1, 'b': 2}) assert handler.check_update({'a': 1, 'b': 2})
assert not handler.check_update(o) assert not handler.check_update(o)
def test_pass_job_or_update_queue(self, dp): def test_context(self, dp):
handler = TypeHandler(dict, self.callback_queue_1, pass_job_queue=True)
dp.add_handler(handler)
dp.process_update({'a': 1, 'b': 2})
assert self.test_flag
dp.remove_handler(handler)
handler = TypeHandler(dict, self.callback_queue_1, pass_update_queue=True)
dp.add_handler(handler)
self.test_flag = False
dp.process_update({'a': 1, 'b': 2})
assert self.test_flag
dp.remove_handler(handler)
handler = TypeHandler(
dict, self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
)
dp.add_handler(handler)
self.test_flag = False
dp.process_update({'a': 1, 'b': 2})
assert self.test_flag
def test_context(self, cdp):
handler = TypeHandler(dict, self.callback_context) handler = TypeHandler(dict, self.callback_context)
cdp.add_handler(handler) dp.add_handler(handler)
cdp.process_update({'a': 1, 'b': 2}) dp.process_update({'a': 1, 'b': 2})
assert self.test_flag assert self.test_flag

View file

@ -106,11 +106,11 @@ class TestUpdater:
self.cb_handler_called.clear() self.cb_handler_called.clear()
self.test_flag = False self.test_flag = False
def error_handler(self, bot, update, error): def error_handler(self, update, context):
self.received = error.message self.received = context.error.message
self.err_handler_called.set() self.err_handler_called.set()
def callback(self, bot, update): def callback(self, update, context):
self.received = update.message.text self.received = update.message.text
self.cb_handler_called.set() self.cb_handler_called.set()
@ -500,10 +500,9 @@ class TestUpdater:
except AssertionError: except AssertionError:
pass pass
assert len(recwarn) == 3 assert len(recwarn) == 2
assert str(recwarn[0].message).startswith('Old Handler API') assert str(recwarn[0].message).startswith('The argument `clean` of')
assert str(recwarn[1].message).startswith('The argument `clean` of') assert str(recwarn[1].message).startswith('The argument `force_event_loop` of')
assert str(recwarn[2].message).startswith('The argument `force_event_loop` of')
def test_clean_deprecation_warning_polling(self, recwarn, updater, monkeypatch): def test_clean_deprecation_warning_polling(self, recwarn, updater, monkeypatch):
monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
@ -522,9 +521,8 @@ class TestUpdater:
except AssertionError: except AssertionError:
pass pass
assert len(recwarn) == 2 assert len(recwarn) == 1
assert str(recwarn[0].message).startswith('Old Handler API') assert str(recwarn[0].message).startswith('The argument `clean` of')
assert str(recwarn[1].message).startswith('The argument `clean` of')
def test_clean_drop_pending_mutually_exclusive(self, updater): def test_clean_drop_pending_mutually_exclusive(self, updater):
with pytest.raises(TypeError, match='`clean` and `drop_pending_updates` are mutually'): with pytest.raises(TypeError, match='`clean` and `drop_pending_updates` are mutually'):
@ -695,12 +693,6 @@ class TestUpdater:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Updater(dispatcher=dispatcher, workers=8) Updater(dispatcher=dispatcher, workers=8)
def test_mutual_exclude_use_context_dispatcher(self, bot):
dispatcher = Dispatcher(bot, None)
use_context = not dispatcher.use_context
with pytest.raises(ValueError):
Updater(dispatcher=dispatcher, use_context=use_context)
def test_mutual_exclude_custom_context_dispatcher(self): def test_mutual_exclude_custom_context_dispatcher(self):
dispatcher = Dispatcher(None, None) dispatcher = Dispatcher(None, None)
with pytest.raises(ValueError): with pytest.raises(ValueError):