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.precheckoutqueryhandler
telegram.ext.prefixhandler
telegram.ext.regexhandler
telegram.ext.shippingqueryhandler
telegram.ext.stringcommandhandler
telegram.ext.stringregexhandler

View file

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

View file

@ -108,10 +108,6 @@ class CallbackContext(Generic[UD, CD, BD]):
Args:
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._chat_id_and_data: Optional[Tuple[int, CD]] = None
self._user_id_and_data: Optional[Tuple[int, UD]] = None

View file

@ -22,7 +22,6 @@ import re
from typing import (
TYPE_CHECKING,
Callable,
Dict,
Match,
Optional,
Pattern,
@ -49,13 +48,6 @@ class CallbackQueryHandler(Handler[Update, CCT]):
Read the 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.
* 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
found. This is the case when either a malicious client tempered with the
@ -72,22 +64,10 @@ class CallbackQueryHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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_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 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
@ -106,66 +86,30 @@ class CallbackQueryHandler(Handler[Update, CCT]):
.. versionchanged:: 13.6
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.
Defaults to :obj:`False`.
Attributes:
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
type to test :attr:`telegram.CallbackQuery.data` against.
.. versionchanged:: 13.6
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.
"""
__slots__ = ('pattern', 'pass_groups', 'pass_groupdict')
__slots__ = ('pattern',)
def __init__(
self,
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,
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,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
run_async=run_async,
)
@ -173,8 +117,6 @@ class CallbackQueryHandler(Handler[Update, CCT]):
pattern = re.compile(pattern)
self.pattern = pattern
self.pass_groups = pass_groups
self.pass_groupdict = pass_groupdict
def check_update(self, update: object) -> Optional[Union[bool, object]]:
"""Determines whether an update should be passed to this handlers :attr:`callback`.
@ -202,25 +144,6 @@ class CallbackQueryHandler(Handler[Update, CCT]):
return True
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(
self,
context: CCT,

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class ChatJoinRequestHandler(Handler[Update, CCT]):
"""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:
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.
@ -52,35 +43,11 @@ class ChatJoinRequestHandler(Handler[Update, CCT]):
The return value of the callback is usually ignored except for the special case of
: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.
Defaults to :obj:`False`.
Attributes:
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.
"""

View file

@ -32,15 +32,6 @@ class ChatMemberHandler(Handler[Update, CCT]):
.. 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:
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.
@ -48,9 +39,7 @@ class ChatMemberHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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`.
@ -58,22 +47,6 @@ class ChatMemberHandler(Handler[Update, CCT]):
:attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle
only updates with :attr:`telegram.Update.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.
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
only updates with :attr:`telegram.Update.my_chat_member`,
: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.
"""
@ -107,18 +72,10 @@ class ChatMemberHandler(Handler[Update, CCT]):
self,
callback: Callable[[Update, CCT], RT],
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,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
run_async=run_async,
)

View file

@ -35,15 +35,6 @@ if TYPE_CHECKING:
class ChosenInlineResultHandler(Handler[Update, CCT]):
"""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:
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.
@ -51,28 +42,10 @@ class ChosenInlineResultHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
pattern (:obj:`str` | `Pattern`, optional): Regex pattern. If not :obj:`None`, ``re.match``
@ -84,14 +57,6 @@ class ChosenInlineResultHandler(Handler[Update, CCT]):
Attributes:
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.
pattern (`Pattern`): Optional. Regex pattern to test
:attr:`telegram.ChosenInlineResult.result_id` against.
@ -105,19 +70,11 @@ class ChosenInlineResultHandler(Handler[Update, CCT]):
def __init__(
self,
callback: Callable[[Update, 'CallbackContext'], RT],
pass_update_queue: bool = False,
pass_job_queue: bool = False,
pass_user_data: bool = False,
pass_chat_data: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
pattern: Union[str, Pattern] = None,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
run_async=run_async,
)

View file

@ -18,12 +18,10 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the CommandHandler and PrefixHandler classes."""
import re
import warnings
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple, TypeVar, Union
from telegram import MessageEntity, Update
from telegram.ext import BaseFilter, Filters
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.types import SLT
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
@ -49,13 +47,6 @@ class CommandHandler(Handler[Update, CCT]):
Note:
* :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:
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
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)``
Callback signature: ``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`.
@ -77,31 +66,6 @@ class CommandHandler(Handler[Update, CCT]):
:class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in
:class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise
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.
Defaults to :obj:`False`.
@ -115,42 +79,20 @@ class CommandHandler(Handler[Update, CCT]):
callback (:obj:`callable`): The callback function for this handler.
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
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.
"""
__slots__ = ('command', 'filters', 'pass_args')
__slots__ = ('command', 'filters')
def __init__(
self,
command: SLT[str],
callback: Callable[[Update, CCT], RT],
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,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
run_async=run_async,
)
@ -167,16 +109,6 @@ class CommandHandler(Handler[Update, CCT]):
else:
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(
self, update: object
) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]:
@ -216,20 +148,6 @@ class CommandHandler(Handler[Update, CCT]):
return False
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(
self,
context: CCT,
@ -282,13 +200,6 @@ class PrefixHandler(CommandHandler):
Note:
* :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:
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.
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)``
Callback signature: ``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`.
@ -311,27 +220,6 @@ class PrefixHandler(CommandHandler):
:class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in
:class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise
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.
Defaults to :obj:`False`.
@ -339,16 +227,6 @@ class PrefixHandler(CommandHandler):
callback (:obj:`callable`): The callback function for this handler.
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
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.
"""
@ -362,11 +240,6 @@ class PrefixHandler(CommandHandler):
command: SLT[str],
callback: Callable[[Update, CCT], RT],
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,
):
@ -378,12 +251,6 @@ class PrefixHandler(CommandHandler):
'nocommand',
callback,
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,
)

View file

@ -53,7 +53,7 @@ class _ConversationTimeoutContext:
conversation_key: Tuple[int, ...],
update: Update,
dispatcher: 'Dispatcher',
callback_context: Optional[CallbackContext],
callback_context: CallbackContext,
):
self.conversation_key = conversation_key
self.update = update
@ -486,7 +486,7 @@ class ConversationHandler(Handler[Update, CCT]):
new_state: object,
dispatcher: 'Dispatcher',
update: Update,
context: Optional[CallbackContext],
context: CallbackContext,
conversation_key: Tuple[int, ...],
) -> None:
if new_state != self.END:
@ -598,7 +598,7 @@ class ConversationHandler(Handler[Update, CCT]):
update: Update,
dispatcher: 'Dispatcher',
check_result: CheckUpdateType,
context: CallbackContext = None,
context: CallbackContext,
) -> Optional[object]:
"""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.
update (:class:`telegram.Update`): Incoming telegram 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.
"""
update = cast(Update, update) # for mypy
conversation_key, handler, check_result = check_result # type: ignore[assignment,misc]
raise_dp_handler_stop = False
@ -690,15 +689,11 @@ class ConversationHandler(Handler[Update, CCT]):
if self.persistent and self.persistence and self.name:
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!')
# Backward compatibility with bots that do not use CallbackContext
if isinstance(context, CallbackContext):
job = context.job
ctxt = cast(_ConversationTimeoutContext, job.context) # type: ignore[union-attr]
else:
ctxt = cast(_ConversationTimeoutContext, job.context)
job = cast('Job', context.job)
ctxt = cast(_ConversationTimeoutContext, job.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.
persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to
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
of :class:`telegram.ext.ContextTypes` to customize the types used in the
``context`` interface. If not passed, the defaults documented in
@ -168,7 +165,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
__slots__ = (
'workers',
'persistence',
'use_context',
'update_queue',
'job_queue',
'user_data',
@ -203,7 +199,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
exception_event: Event = None,
job_queue: 'JobQueue' = None,
persistence: BasePersistence = None,
use_context: bool = True,
):
...
@ -216,7 +211,6 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
exception_event: Event = None,
job_queue: 'JobQueue' = None,
persistence: BasePersistence = None,
use_context: bool = True,
context_types: ContextTypes[CCT, UD, CD, BD] = None,
):
...
@ -229,23 +223,14 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
exception_event: Event = None,
job_queue: 'JobQueue' = None,
persistence: BasePersistence = None,
use_context: bool = True,
context_types: ContextTypes[CCT, UD, CD, BD] = None,
):
self.bot = bot
self.update_queue = update_queue
self.job_queue = job_queue
self.workers = workers
self.use_context = use_context
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:
warnings.warn(
'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]:
check = handler.check_update(update)
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.refresh_data()
handled = True
@ -743,16 +728,12 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
Args:
callback (:obj:`callable`): The callback function for this error handler. Will be
called when an error is raised. Callback signature for context based API:
``def callback(update: object, context: CallbackContext)``
called when an error is raised.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
The error that happened will be present in context.error.
run_async (:obj:`bool`, optional): Whether this handlers callback should be run
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:
self.logger.debug('The callback is already registered as an error handler. Ignoring.')
@ -789,19 +770,13 @@ class Dispatcher(Generic[CCT, UD, CD, BD]):
if self.error_handlers:
for callback, run_async in self.error_handlers.items(): # pylint: disable=W0621
if self.use_context:
context = self.context_types.context.from_error(
update, error, self, async_args=async_args, async_kwargs=async_kwargs
)
if run_async:
self.run_async(callback, update, context, update=update)
else:
callback(update, context)
context = self.context_types.context.from_error(
update, error, self, async_args=async_args, async_kwargs=async_kwargs
)
if run_async:
self.run_async(callback, update, context, update=update)
else:
if run_async:
self.run_async(callback, self.bot, update, error, update=update)
else:
callback(self.bot, update, error)
callback(update, context)
else:
self.logger.exception(

View file

@ -18,9 +18,8 @@
# 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."""
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.utils.helpers import DefaultValue, DEFAULT_FALSE
from telegram.ext.utils.types import CCT
@ -35,15 +34,6 @@ UT = TypeVar('UT')
class Handler(Generic[UT, CCT], ABC):
"""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:
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.
@ -51,68 +41,30 @@ class Handler(Generic[UT, CCT], ABC):
Args:
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
Attributes:
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.
"""
__slots__ = (
'callback',
'pass_update_queue',
'pass_job_queue',
'pass_user_data',
'pass_chat_data',
'run_async',
)
def __init__(
self,
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,
):
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
@abstractmethod
@ -140,7 +92,7 @@ class Handler(Generic[UT, CCT], ABC):
update: UT,
dispatcher: 'Dispatcher',
check_result: object,
context: CCT = None,
context: CCT,
) -> Union[RT, Promise]:
"""
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.
dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher.
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.
"""
@ -165,18 +117,10 @@ class Handler(Generic[UT, CCT], ABC):
):
run_async = True
if context:
self.collect_additional_context(context, update, dispatcher, check_result)
if run_async:
return dispatcher.run_async(self.callback, update, context, update=update)
return self.callback(update, context)
optional_args = self.collect_optional_args(dispatcher, update, check_result)
self.collect_additional_context(context, update, dispatcher, 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
return dispatcher.run_async(self.callback, update, context, update=update)
return self.callback(update, context)
def collect_additional_context(
self,
@ -194,41 +138,3 @@ class Handler(Generic[UT, CCT], ABC):
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 (
TYPE_CHECKING,
Callable,
Dict,
Match,
Optional,
Pattern,
@ -48,15 +47,6 @@ class InlineQueryHandler(Handler[Update, CCT]):
Handler class to handle Telegram inline queries. Optionally based on a regex. Read the
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:
* 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.
@ -67,22 +57,10 @@ class InlineQueryHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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_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`,
``re.match`` is used on :attr:`telegram.InlineQuery.query` to determine if an update
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`.
.. 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.
Defaults to :obj:`False`.
Attributes:
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
:attr:`telegram.InlineQuery.query` against.
chat_types (List[:obj:`str`], optional): List of allowed chat types.
.. 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.
"""
__slots__ = ('pattern', 'chat_types', 'pass_groups', 'pass_groupdict')
__slots__ = ('pattern', 'chat_types')
def __init__(
self,
callback: Callable[[Update, CCT], RT],
pass_update_queue: bool = False,
pass_job_queue: bool = False,
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,
chat_types: List[str] = None,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
run_async=run_async,
)
@ -159,8 +101,6 @@ class InlineQueryHandler(Handler[Update, CCT]):
self.pattern = pattern
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]]:
"""
@ -187,25 +127,6 @@ class InlineQueryHandler(Handler[Update, CCT]):
return True
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(
self,
context: CCT,

View file

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

View file

@ -16,14 +16,11 @@
#
# 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 MessageHandler class."""
import warnings
from typing import TYPE_CHECKING, Callable, Dict, Optional, TypeVar, Union
from telegram import Update
from telegram.ext import BaseFilter, Filters
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
from .handler import Handler
@ -38,15 +35,6 @@ RT = TypeVar('RT')
class MessageHandler(Handler[Update, CCT]):
"""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:
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.
@ -62,37 +50,10 @@ class MessageHandler(Handler[Update, CCT]):
argument.
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
@ -103,20 +64,6 @@ class MessageHandler(Handler[Update, CCT]):
filters (:obj:`Filter`): Only allow updates with these Filters. See
:mod:`telegram.ext.filters` for a full list of all available filters.
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.
"""
@ -127,60 +74,17 @@ class MessageHandler(Handler[Update, CCT]):
self,
filters: BaseFilter,
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,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
pass_user_data=pass_user_data,
pass_chat_data=pass_chat_data,
run_async=run_async,
)
if 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:
self.filters = Filters.update & filters
else:
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]]]:
"""Determines whether an update should be passed to this handlers :attr:`callback`.
@ -192,7 +96,7 @@ class MessageHandler(Handler[Update, CCT]):
:obj:`bool`
"""
if isinstance(update, Update) and update.effective_message:
if isinstance(update, Update):
return self.filters(update)
return None

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class PollAnswerHandler(Handler[Update, CCT]):
"""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:
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.
@ -44,41 +35,15 @@ class PollAnswerHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
Attributes:
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.
"""

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class PollHandler(Handler[Update, CCT]):
"""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:
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.
@ -44,41 +35,15 @@ class PollHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
Attributes:
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.
"""

View file

@ -28,15 +28,6 @@ from .utils.types import CCT
class PreCheckoutQueryHandler(Handler[Update, CCT]):
"""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:
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.
@ -44,41 +35,15 @@ class PreCheckoutQueryHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
Attributes:
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.
"""

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]):
"""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:
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.
@ -43,41 +34,15 @@ class ShippingQueryHandler(Handler[Update, CCT]):
Args:
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
Attributes:
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.
"""

View file

@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""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
@ -49,62 +49,33 @@ class StringCommandHandler(Handler[str, CCT]):
command (:obj:`str`): The command this handler should listen for.
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)``
Callback signature: ``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_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.
Defaults to :obj:`False`.
Attributes:
command (:obj:`str`): The command this handler should listen for.
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.
"""
__slots__ = ('command', 'pass_args')
__slots__ = ('command',)
def __init__(
self,
command: str,
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,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
run_async=run_async,
)
self.command = command
self.pass_args = pass_args
def check_update(self, update: object) -> Optional[List[str]]:
"""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 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(
self,
context: CCT,

View file

@ -19,7 +19,7 @@
"""This module contains the StringRegexHandler class."""
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
@ -50,64 +50,30 @@ class StringRegexHandler(Handler[str, CCT]):
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)``
Callback signature: ``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`
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.
Defaults to :obj:`False`.
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.
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
"""
__slots__ = ('pass_groups', 'pass_groupdict', 'pattern')
__slots__ = ('pattern',)
def __init__(
self,
pattern: Union[str, Pattern],
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,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
run_async=run_async,
)
@ -115,8 +81,6 @@ class StringRegexHandler(Handler[str, CCT]):
pattern = re.compile(pattern)
self.pattern = pattern
self.pass_groups = pass_groups
self.pass_groupdict = pass_groupdict
def check_update(self, update: object) -> Optional[Match]:
"""Determines whether an update should be passed to this handlers :attr:`callback`.
@ -134,24 +98,6 @@ class StringRegexHandler(Handler[str, CCT]):
return match
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(
self,
context: CCT,

View file

@ -40,24 +40,12 @@ class TypeHandler(Handler[UT, CCT]):
determined by ``isinstance``
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)``
Callback signature: ``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`.
strict (:obj:`bool`, optional): Use ``type`` instead of ``isinstance``.
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.
Defaults to :obj:`False`.
@ -65,10 +53,6 @@ class TypeHandler(Handler[UT, CCT]):
type (:obj:`type`): The ``type`` of updates this handler should process.
callback (:obj:`callable`): The callback function for this handler.
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.
"""
@ -80,14 +64,10 @@ class TypeHandler(Handler[UT, CCT]):
type: Type[UT], # pylint: disable=W0622
callback: Callable[[UT, CCT], RT],
strict: bool = False,
pass_update_queue: bool = False,
pass_job_queue: bool = False,
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
):
super().__init__(
callback,
pass_update_queue=pass_update_queue,
pass_job_queue=pass_job_queue,
run_async=run_async,
)
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
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.
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
store data that should be persistent over restarts (ignored if `dispatcher` argument is
used).
@ -129,7 +126,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
running (:obj:`bool`): Indicates if the updater is running.
persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to
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,
persistence: 'BasePersistence' = None, # pylint: disable=E0601
defaults: 'Defaults' = None,
use_context: bool = True,
base_file_url: str = None,
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,
persistence: 'BasePersistence' = None,
defaults: 'Defaults' = None,
use_context: bool = True,
base_file_url: str = None,
arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE,
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,
persistence: 'BasePersistence' = None,
defaults: 'Defaults' = None,
use_context: bool = True,
dispatcher=None,
base_file_url: str = None,
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')
if persistence is not None:
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:
raise ValueError('`dispatcher` and `context_types` are mutually exclusive')
if workers is not None:
@ -300,7 +291,6 @@ class Updater(Generic[CCT, UD, CD, BD]):
workers=workers,
exception_event=self.__exception_event,
persistence=persistence,
use_context=use_context,
context_types=context_types,
)
self.job_queue.set_dispatcher(self.dispatcher)

View file

@ -159,7 +159,7 @@ def provider_token(bot_info):
def create_dp(bot):
# 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)
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)
thr = Thread(target=dispatcher.start)
thr.start()
@ -195,23 +195,15 @@ def dp(_dp):
object.__setattr__(_dp, '__async_queue', Queue())
object.__setattr__(_dp, '__async_threads', set())
_dp.persistence = None
_dp.use_context = False
if _dp._Dispatcher__singleton_semaphore.acquire(blocking=0):
Dispatcher._set_singleton(_dp)
yield _dp
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')
def updater(bot):
up = Updater(bot=bot, workers=2, use_context=False)
up = Updater(bot=bot, workers=2)
yield up
if up.running:
up.stop()

View file

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

View file

@ -82,8 +82,8 @@ class TestCallbackQueryHandler:
def reset(self):
self.test_flag = False
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
def callback_basic(self, update, context):
test_bot = isinstance(context.bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
@ -124,15 +124,6 @@ class TestCallbackQueryHandler:
if context.matches[0].groupdict():
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):
handler = CallbackQueryHandler(self.callback_basic, pattern='.*est.*')
@ -177,103 +168,34 @@ class TestCallbackQueryHandler:
callback_query.callback_query.data = 'callback_data'
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):
handler = CallbackQueryHandler(self.callback_basic)
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update(callback_query)
dp.process_update(callback_query)
assert self.test_flag
def test_context_pattern(self, cdp, callback_query):
def test_context_pattern(self, dp, callback_query):
handler = CallbackQueryHandler(
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
cdp.remove_handler(handler)
dp.remove_handler(handler)
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
def test_context_callable_pattern(self, cdp, callback_query):
def test_context_callable_pattern(self, dp, callback_query):
class CallbackData:
pass
@ -284,6 +206,6 @@ class TestCallbackQueryHandler:
assert context.matches is None
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
def test_slot_behaviour(self, recwarn, mro_slots):
action = ChatJoinRequestHandler(self.callback_basic)
action = ChatJoinRequestHandler(self.callback_context)
for attr in action.__slots__:
assert getattr(action, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
@ -111,23 +111,6 @@ class TestChatJoinRequestHandler:
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_context(self, update, context):
self.test_flag = (
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):
handler = ChatJoinRequestHandler(self.callback_basic)
handler = ChatJoinRequestHandler(self.callback_context)
assert not handler.check_update(false_update)
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)
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

View file

@ -89,7 +89,7 @@ class TestChatMemberHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
action = ChatMemberHandler(self.callback_basic)
action = ChatMemberHandler(self.callback_context)
for attr in action.__slots__:
assert getattr(action, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot"
@ -98,23 +98,6 @@ class TestChatMemberHandler:
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_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
@ -128,15 +111,6 @@ class TestChatMemberHandler:
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(
argnames=['allowed_types', 'expected'],
argvalues=[
@ -151,7 +125,7 @@ class TestChatMemberHandler:
):
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)
assert handler.check_update(chat_member) == result_1
@ -166,62 +140,14 @@ class TestChatMemberHandler:
dp.process_update(chat_member)
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):
handler = ChatMemberHandler(self.callback_basic)
handler = ChatMemberHandler(self.callback_context)
assert not handler.check_update(false_update)
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update(chat_member)
dp.process_update(chat_member)
assert self.test_flag

View file

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

View file

@ -20,8 +20,6 @@ import re
from queue import Queue
import pytest
import itertools
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram import Message, Update, Chat, Bot
from telegram.ext import CommandHandler, Filters, CallbackContext, JobQueue, PrefixHandler
@ -56,12 +54,6 @@ class BaseTest:
def reset(self):
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):
"""
Utility to send an update to a dispatcher and assert
@ -72,8 +64,8 @@ class BaseTest:
dispatcher.process_update(update)
return self.test_flag
def callback_basic(self, bot, update):
test_bot = isinstance(bot, Bot)
def callback_basic(self, update, context):
test_bot = isinstance(context.bot, Bot)
test_update = isinstance(update, Update)
self.test_flag = test_bot and test_update
@ -112,12 +104,12 @@ class BaseTest:
num = len(context.matches) == 2
self.test_flag = types and num
def _test_context_args_or_regex(self, cdp, handler, text):
cdp.add_handler(handler)
def _test_context_args_or_regex(self, dp, handler, text):
dp.add_handler(handler)
update = make_command_update(text)
assert not self.response(cdp, update)
assert not self.response(dp, update)
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):
"""
@ -160,14 +152,6 @@ class TestCommandHandler(BaseTest):
def command_update(self, 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):
callback = callback or self.callback_basic
return CommandHandler(self.CMD[1:], callback, **kwargs)
@ -199,23 +183,12 @@ class TestCommandHandler(BaseTest):
assert is_match(handler, make_command_update('/star'))
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):
"""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_no_edited = self.make_default_handler(filters=~Filters.update.edited_message)
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):
"""Test recognition of commands with a mention to the bot"""
handler = self.make_default_handler()
@ -223,21 +196,11 @@ class TestCommandHandler(BaseTest):
assert not is_match(handler, make_command_update(command + '@otherbot', bot=bot))
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)
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)))
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):
"""Assert that newlines don't interfere with a command handler matching a message"""
handler = self.make_default_handler()
@ -246,12 +209,6 @@ class TestCommandHandler(BaseTest):
assert is_match(handler, 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):
"""Test that a command handler doesn't respond to unrelated updates"""
handler = self.make_default_handler()
@ -263,30 +220,30 @@ class TestCommandHandler(BaseTest):
assert not is_match(handler, make_command_update('/star'))
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"""
handler = self.make_default_handler(self.callback_context)
cdp.add_handler(handler)
assert self.response(cdp, command_update)
dp.add_handler(handler)
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``"""
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"""
handler = self.make_default_handler(
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"""
handler = self.make_default_handler(
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 -----------------------------
@ -340,12 +297,6 @@ class TestPrefixHandler(BaseTest):
callback = callback or self.callback_basic
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):
"""Test the basic expected response from a prefix 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 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):
handler = self.make_default_handler()
assert not is_match(handler, false_update)
@ -427,23 +359,23 @@ class TestPrefixHandler(BaseTest):
text = prefix + 'foo'
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)
cdp.add_handler(handler)
assert self.response(cdp, prefix_message_update)
dp.add_handler(handler)
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)
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(
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(
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
@raise_dphs
def start(self, bot, update):
def start(self, update, context):
if isinstance(update, Update):
return self._set_state(update, self.THIRSTY)
return self._set_state(bot, self.THIRSTY)
return self._set_state(context.bot, self.THIRSTY)
@raise_dphs
def end(self, bot, update):
def end(self, update, context):
return self._set_state(update, self.END)
@raise_dphs
def start_end(self, bot, update):
def start_end(self, update, context):
return self._set_state(update, self.END)
@raise_dphs
def start_none(self, bot, update):
def start_none(self, update, context):
return self._set_state(update, None)
@raise_dphs
def brew(self, bot, update):
def brew(self, update, context):
if isinstance(update, Update):
return self._set_state(update, self.BREWING)
return self._set_state(bot, self.BREWING)
return self._set_state(context.bot, self.BREWING)
@raise_dphs
def drink(self, bot, update):
def drink(self, update, context):
return self._set_state(update, self.DRINKING)
@raise_dphs
def code(self, bot, update):
def code(self, update, context):
return self._set_state(update, self.CODING)
@raise_dphs
def passout(self, bot, update):
def passout(self, update, context):
assert update.message.text == '/brew'
assert isinstance(update, Update)
self.is_timeout = True
@raise_dphs
def passout2(self, bot, update):
def passout2(self, update, context):
assert isinstance(update, Update)
self.is_timeout = True
@ -226,23 +226,23 @@ class TestConversationHandler:
# Drinking actions (nested)
@raise_dphs
def hold(self, bot, update):
def hold(self, update, context):
return self._set_state(update, self.HOLDING)
@raise_dphs
def sip(self, bot, update):
def sip(self, update, context):
return self._set_state(update, self.SIPPING)
@raise_dphs
def swallow(self, bot, update):
def swallow(self, update, context):
return self._set_state(update, self.SWALLOWING)
@raise_dphs
def replenish(self, bot, update):
def replenish(self, update, context):
return self._set_state(update, self.REPLENISHING)
@raise_dphs
def stop(self, bot, update):
def stop(self, update, context):
return self._set_state(update, self.STOPPING)
# Tests
@ -543,13 +543,13 @@ class TestConversationHandler:
assert handler.conversations[(user1.id,)] == self.DRINKING
def test_conversation_handler_per_message(self, dp, bot, user1, user2):
def entry(bot, update):
def entry(update, context):
return 1
def one(bot, update):
def one(update, context):
return 2
def two(bot, update):
def two(update, context):
return ConversationHandler.END
handler = ConversationHandler(
@ -606,7 +606,7 @@ class TestConversationHandler:
handler = ConversationHandler(
entry_points=[
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={},
@ -687,7 +687,7 @@ class TestConversationHandler:
handler = ConversationHandler(
entry_points=[
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={},
@ -1026,7 +1026,7 @@ class TestConversationHandler:
rec = caplog.records[-1]
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
def start_callback(u, c):
@ -1043,7 +1043,7 @@ class TestConversationHandler:
fallbacks=self.fallbacks,
conversation_timeout=0.5,
)
cdp.add_handler(handler)
dp.add_handler(handler)
# Start state machine, then reach timeout
message = Message(
@ -1067,7 +1067,7 @@ class TestConversationHandler:
timeout_handler.callback = timeout_callback
cdp.process_update(update)
dp.process_update(update)
sleep(0.7)
assert handler.conversations.get((self.group.id, user1.id)) is None
assert self.is_timeout
@ -1216,7 +1216,7 @@ class TestConversationHandler:
assert handler.conversations.get((self.group.id, user1.id)) is None
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.update(
{
@ -1232,7 +1232,7 @@ class TestConversationHandler:
fallbacks=self.fallbacks,
conversation_timeout=0.5,
)
cdp.add_handler(handler)
dp.add_handler(handler)
# CommandHandler timeout
message = Message(
@ -1246,10 +1246,10 @@ class TestConversationHandler:
],
bot=bot,
)
cdp.process_update(Update(update_id=0, message=message))
dp.process_update(Update(update_id=0, message=message))
message.text = '/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)
assert handler.conversations.get((self.group.id, user1.id)) is None
assert self.is_timeout
@ -1258,20 +1258,20 @@ class TestConversationHandler:
self.is_timeout = False
message.text = '/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)
assert handler.conversations.get((self.group.id, user1.id)) is None
assert self.is_timeout
# Timeout but no valid handler
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.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.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)
assert handler.conversations.get((self.group.id, user1.id)) is None
assert not self.is_timeout
@ -1285,7 +1285,7 @@ class TestConversationHandler:
# | t=.75 /slowbrew returns (timeout=1.25)
# t=1.25 timeout
def slowbrew(_bot, update):
def slowbrew(_update, context):
sleep(0.25)
# Let's give to the original timeout a chance to execute
sleep(0.25)
@ -1395,10 +1395,10 @@ class TestConversationHandler:
)
def test_warnings_per_chat_is_only_shown_once(self, recwarn):
def hello(bot, update):
def hello(update, context):
return self.BREWING
def bye(bot, update):
def bye(update, context):
return ConversationHandler.END
ConversationHandler(

View file

@ -30,7 +30,7 @@ class TestDefault:
assert getattr(a, attr, 'err') != 'err', f"got extra slot '{attr}'"
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()
with pytest.raises(AttributeError):

View file

@ -72,16 +72,13 @@ class TestDispatcher:
self.received = None
self.count = 0
def error_handler(self, bot, update, error):
self.received = error.message
def error_handler_context(self, update, context):
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')
def callback_increase_count(self, bot, update):
def callback_increase_count(self, update, context):
self.count += 1
def callback_set_count(self, count):
@ -90,14 +87,11 @@ class TestDispatcher:
return callback
def callback_raise_error(self, bot, update):
if isinstance(bot, Bot):
raise TelegramError(update.message.text)
raise TelegramError(bot.message.text)
def callback_raise_error(self, update, context):
raise TelegramError(update.message.text)
def callback_if_not_update_queue(self, bot, update, update_queue=None):
if update_queue is not None:
self.received = update.message
def callback_received(self, update, context):
self.received = update.message
def callback_context(self, update, context):
if (
@ -110,14 +104,14 @@ class TestDispatcher:
self.received = context.error.message
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 (
str(recwarn[0].message)
== '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):
if update.message.text == 'test':
context.my_flag = True
@ -130,22 +124,22 @@ class TestDispatcher:
if hasattr(context, 'my_flag'):
pytest.fail()
cdp.add_handler(MessageHandler(Filters.regex('test'), one), group=1)
cdp.add_handler(MessageHandler(None, two), group=2)
dp.add_handler(MessageHandler(Filters.regex('test'), one), group=1)
dp.add_handler(MessageHandler(None, two), group=2)
u = Update(1, Message(1, None, None, None, text='test'))
cdp.process_update(u)
dp.process_update(u)
u.message.text = 'something'
cdp.process_update(u)
dp.process_update(u)
def test_error_handler(self, dp):
dp.add_error_handler(self.error_handler)
dp.add_error_handler(self.error_handler_context)
error = TelegramError('Unauthorized.')
dp.update_queue.put(error)
sleep(0.1)
assert self.received == 'Unauthorized.'
# Remove handler
dp.remove_error_handler(self.error_handler)
dp.remove_error_handler(self.error_handler_context)
self.reset()
dp.update_queue.put(error)
@ -153,9 +147,9 @@ class TestDispatcher:
assert self.received is None
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):
dp.add_error_handler(self.error_handler)
dp.add_error_handler(self.error_handler_context)
assert len(caplog.records) == 1
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)
try:
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)
dp.process_update(self.message_update)
@ -262,17 +256,6 @@ class TestDispatcher:
with pytest.raises(RuntimeError):
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):
assert isinstance(dp, Dispatcher)
@ -323,8 +306,7 @@ class TestDispatcher:
dp.add_handler(
MessageHandler(
Filters.all,
self.callback_if_not_update_queue,
pass_update_queue=True,
self.callback_received,
run_async=True,
)
)
@ -343,19 +325,11 @@ class TestDispatcher:
assert len(caplog.records) == 1
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_error_handler(self.error_handler)
dp.add_error_handler(self.error_handler_context, run_async=True)
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)
assert self.received == self.message_update.message.text
@ -397,7 +371,7 @@ class TestDispatcher:
def test_error_in_handler(self, dp):
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)
sleep(0.1)
@ -494,19 +468,19 @@ class TestDispatcher:
passed = []
err = Exception('General exception')
def start1(b, u):
def start1(u, c):
passed.append('start1')
raise err
def start2(b, u):
def start2(u, c):
passed.append('start2')
def start3(b, u):
def start3(u, c):
passed.append('start3')
def error(b, u, e):
def error(u, c):
passed.append('error')
passed.append(e)
passed.append(c.error)
update = Update(
1,
@ -537,19 +511,19 @@ class TestDispatcher:
passed = []
err = TelegramError('Telegram error')
def start1(b, u):
def start1(u, c):
passed.append('start1')
raise err
def start2(b, u):
def start2(u, c):
passed.append('start2')
def start3(b, u):
def start3(u, c):
passed.append('start3')
def error(b, u, e):
def error(u, c):
passed.append('error')
passed.append(e)
passed.append(c.error)
update = Update(
1,
@ -622,10 +596,10 @@ class TestDispatcher:
def flush(self):
pass
def start1(b, u):
def start1(u, c):
pass
def error(b, u, e):
def error(u, c):
increment.append("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()
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_error_handler(error)
dp.process_update(update)
@ -656,19 +630,19 @@ class TestDispatcher:
passed = []
err = TelegramError('Telegram error')
def start1(b, u):
def start1(u, c):
passed.append('start1')
raise err
def start2(b, u):
def start2(u, c):
passed.append('start2')
def start3(b, u):
def start3(u, c):
passed.append('start3')
def error(b, u, e):
def error(u, c):
passed.append('error')
passed.append(e)
passed.append(c.error)
raise DispatcherHandlerStop
update = Update(
@ -696,26 +670,12 @@ class TestDispatcher:
assert passed == ['start1', 'error', 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):
thread_names = [thread.name for thread in dp2._Dispatcher__async_threads]
for thread_name in thread_names:
assert thread_name.startswith(f"Bot:{dp2.bot.id}:worker:")
def test_non_context_deprecation(self, dp):
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):
def test_error_while_persisting(self, dp, monkeypatch):
class OwnPersistence(BasePersistence):
def update(self, data):
raise Exception('PersistenceError')
@ -779,15 +739,15 @@ class TestDispatcher:
1, message=Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')
)
handler = MessageHandler(Filters.all, callback)
cdp.add_handler(handler)
cdp.add_error_handler(error)
monkeypatch.setattr(cdp.logger, 'exception', logger)
dp.add_handler(handler)
dp.add_error_handler(error)
monkeypatch.setattr(dp.logger, 'exception', logger)
cdp.persistence = OwnPersistence()
cdp.process_update(update)
dp.persistence = OwnPersistence()
dp.process_update(update)
assert test_flag
def test_persisting_no_user_no_chat(self, cdp):
def test_persisting_no_user_no_chat(self, dp):
class OwnPersistence(BasePersistence):
def __init__(self):
super().__init__()
@ -841,25 +801,25 @@ class TestDispatcher:
pass
handler = MessageHandler(Filters.all, callback)
cdp.add_handler(handler)
cdp.persistence = OwnPersistence()
dp.add_handler(handler)
dp.persistence = OwnPersistence()
update = Update(
1, message=Message(1, None, None, from_user=User(1, '', False), text='Text')
)
cdp.process_update(update)
assert cdp.persistence.test_flag_bot_data
assert cdp.persistence.test_flag_user_data
assert not cdp.persistence.test_flag_chat_data
dp.process_update(update)
assert dp.persistence.test_flag_bot_data
assert dp.persistence.test_flag_user_data
assert not dp.persistence.test_flag_chat_data
cdp.persistence.test_flag_bot_data = False
cdp.persistence.test_flag_user_data = False
cdp.persistence.test_flag_chat_data = False
dp.persistence.test_flag_bot_data = False
dp.persistence.test_flag_user_data = False
dp.persistence.test_flag_chat_data = False
update = Update(1, message=Message(1, None, Chat(1, ''), from_user=None, text='Text'))
cdp.process_update(update)
assert cdp.persistence.test_flag_bot_data
assert not cdp.persistence.test_flag_user_data
assert cdp.persistence.test_flag_chat_data
dp.process_update(update)
assert dp.persistence.test_flag_bot_data
assert not dp.persistence.test_flag_user_data
assert dp.persistence.test_flag_chat_data
def test_update_persistence_once_per_update(self, monkeypatch, dp):
def update_persistence(*args, **kwargs):

View file

@ -94,29 +94,6 @@ class TestInlineQueryHandler:
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', ' query')
if groupdict is not None:
self.test_flag = groupdict == {'begin': 't', 'end': ' query'}
def callback_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
@ -136,130 +113,44 @@ class TestInlineQueryHandler:
if context.matches[0].groupdict():
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):
handler = InlineQueryHandler(self.callback_basic)
handler = InlineQueryHandler(self.callback_context)
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update(inline_query)
dp.process_update(inline_query)
assert self.test_flag
def test_context_pattern(self, cdp, inline_query):
def test_context_pattern(self, dp, inline_query):
handler = InlineQueryHandler(
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
cdp.remove_handler(handler)
dp.remove_handler(handler)
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
@pytest.mark.parametrize('chat_types', [[Chat.SENDER], [Chat.SENDER, Chat.SUPERGROUP], []])
@pytest.mark.parametrize(
'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:
inline_query.inline_query.chat_type = chat_type
handler = InlineQueryHandler(self.callback_context, chat_types=chat_types)
cdp.add_handler(handler)
cdp.process_update(inline_query)
dp.add_handler(handler)
dp.process_update(inline_query)
if not chat_types:
assert self.test_flag is False

View file

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

View file

@ -20,7 +20,6 @@ import re
from queue import Queue
import pytest
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram import (
Message,
@ -72,7 +71,7 @@ class TestMessageHandler:
SRE_TYPE = type(re.match("", ""))
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__:
assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
@ -81,23 +80,6 @@ class TestMessageHandler:
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_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
@ -137,75 +119,8 @@ class TestMessageHandler:
num = len(context.matches) == 2
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):
handler = MessageHandler(Filters.group, self.callback_basic)
handler = MessageHandler(Filters.group, self.callback_context)
message.chat.type = 'group'
assert handler.check_update(Update(0, message))
@ -221,7 +136,7 @@ class TestMessageHandler:
self.flag = True
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))
@ -235,110 +150,61 @@ class TestMessageHandler:
& ~Filters.update.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, message=message))
assert not handler.check_update(Update(0, 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):
handler = MessageHandler(None, self.callback_basic, edited_updates=True)
handler = MessageHandler(None, self.callback_context)
assert not handler.check_update(false_update)
def test_context(self, cdp, message):
def test_context(self, dp, message):
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
self.test_flag = False
cdp.process_update(Update(0, edited_message=message))
dp.process_update(Update(0, edited_message=message))
assert self.test_flag
self.test_flag = False
cdp.process_update(Update(0, channel_post=message))
dp.process_update(Update(0, channel_post=message))
assert self.test_flag
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
def test_context_regex(self, cdp, message):
def test_context_regex(self, dp, message):
handler = MessageHandler(Filters.regex('one two'), self.callback_context_regex1)
cdp.add_handler(handler)
dp.add_handler(handler)
message.text = 'not it'
cdp.process_update(Update(0, message))
dp.process_update(Update(0, message))
assert not self.test_flag
message.text += ' one two now it is'
cdp.process_update(Update(0, message))
dp.process_update(Update(0, message))
assert self.test_flag
def test_context_multiple_regex(self, cdp, message):
def test_context_multiple_regex(self, dp, message):
handler = MessageHandler(
Filters.regex('one') & Filters.regex('two'), self.callback_context_regex2
)
cdp.add_handler(handler)
dp.add_handler(handler)
message.text = 'not it'
cdp.process_update(Update(0, message))
dp.process_update(Update(0, message))
assert not self.test_flag
message.text += ' one two now it is'
cdp.process_update(Update(0, message))
dp.process_update(Update(0, message))
assert self.test_flag

View file

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

View file

@ -75,7 +75,7 @@ class TestPollAnswerHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
handler = PollAnswerHandler(self.callback_basic)
handler = PollAnswerHandler(self.callback_context)
for attr in handler.__slots__:
assert getattr(handler, attr, 'err') != 'err', f"got extra slot '{attr}'"
assert len(mro_slots(handler)) == len(set(mro_slots(handler))), "duplicate slot"
@ -84,23 +84,6 @@ class TestPollAnswerHandler:
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_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
@ -114,70 +97,13 @@ class TestPollAnswerHandler:
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):
handler = PollAnswerHandler(self.callback_basic)
handler = PollAnswerHandler(self.callback_context)
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update(poll_answer)
dp.process_update(poll_answer)
assert self.test_flag

View file

@ -88,7 +88,7 @@ class TestPollHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
inst = PollHandler(self.callback_basic)
inst = PollHandler(self.callback_context)
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"
@ -97,23 +97,6 @@ class TestPollHandler:
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_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
@ -127,68 +110,13 @@ class TestPollHandler:
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):
handler = PollHandler(self.callback_basic)
handler = PollHandler(self.callback_context)
assert not handler.check_update(false_update)
def test_context(self, cdp, poll):
def test_context(self, dp, poll):
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

View file

@ -80,7 +80,7 @@ class TestPreCheckoutQueryHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
inst = PreCheckoutQueryHandler(self.callback_basic)
inst = PreCheckoutQueryHandler(self.callback_context)
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"
@ -89,23 +89,6 @@ class TestPreCheckoutQueryHandler:
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_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
@ -119,71 +102,13 @@ class TestPreCheckoutQueryHandler:
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):
handler = PreCheckoutQueryHandler(self.callback_basic)
handler = PreCheckoutQueryHandler(self.callback_context)
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update(pre_checkout_query)
dp.process_update(pre_checkout_query)
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
def test_slot_behaviour(self, mro_slots):
inst = ShippingQueryHandler(self.callback_basic)
inst = ShippingQueryHandler(self.callback_context)
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"
@ -93,23 +93,6 @@ class TestShippingQueryHandler:
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_context(self, update, context):
self.test_flag = (
isinstance(context, CallbackContext)
@ -123,71 +106,13 @@ class TestShippingQueryHandler:
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):
handler = ShippingQueryHandler(self.callback_basic)
handler = ShippingQueryHandler(self.callback_context)
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update(shiping_query)
dp.process_update(shiping_query)
assert self.test_flag

View file

@ -72,7 +72,7 @@ class TestStringCommandHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
inst = StringCommandHandler('sleepy', self.callback_basic)
inst = StringCommandHandler('sleepy', self.callback_context)
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"
@ -81,23 +81,6 @@ class TestStringCommandHandler:
def reset(self):
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):
self.test_flag = (
isinstance(context, CallbackContext)
@ -113,75 +96,23 @@ class TestStringCommandHandler:
def callback_context_args(self, update, context):
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):
handler = StringCommandHandler('test', self.callback_basic)
handler = StringCommandHandler('test', self.callback_context)
assert not handler.check_update(false_update)
def test_context(self, cdp):
def test_context(self, dp):
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
def test_context_args(self, cdp):
def test_context_args(self, dp):
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
cdp.process_update('/test one two')
dp.process_update('/test one two')
assert self.test_flag

View file

@ -72,7 +72,7 @@ class TestStringRegexHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
inst = StringRegexHandler('pfft', self.callback_basic)
inst = StringRegexHandler('pfft', self.callback_context)
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"
@ -81,23 +81,6 @@ class TestStringRegexHandler:
def reset(self):
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):
self.test_flag = (
isinstance(context, CallbackContext)
@ -114,7 +97,7 @@ class TestStringRegexHandler:
self.test_flag = context.matches[0].groupdict() == {'begin': 't', 'end': ' message'}
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)
assert handler.check_update('test message')
@ -123,71 +106,27 @@ class TestStringRegexHandler:
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):
handler = StringRegexHandler('test', self.callback_basic)
handler = StringRegexHandler('test', self.callback_context)
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update('test message')
dp.process_update('test message')
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)
cdp.add_handler(handler)
dp.add_handler(handler)
cdp.process_update('test message')
dp.process_update('test message')
assert self.test_flag
cdp.remove_handler(handler)
dp.remove_handler(handler)
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

View file

@ -29,7 +29,7 @@ class TestTypeHandler:
test_flag = False
def test_slot_behaviour(self, mro_slots):
inst = TypeHandler(dict, self.callback_basic)
inst = TypeHandler(dict, self.callback_context)
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"
@ -38,17 +38,6 @@ class TestTypeHandler:
def reset(self):
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):
self.test_flag = (
isinstance(context, CallbackContext)
@ -62,7 +51,7 @@ class TestTypeHandler:
)
def test_basic(self, dp):
handler = TypeHandler(dict, self.callback_basic)
handler = TypeHandler(dict, self.callback_context)
dp.add_handler(handler)
assert handler.check_update({'a': 1, 'b': 2})
@ -71,39 +60,14 @@ class TestTypeHandler:
assert self.test_flag
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})
assert handler.check_update({'a': 1, 'b': 2})
assert not handler.check_update(o)
def test_pass_job_or_update_queue(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):
def test_context(self, dp):
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

View file

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