mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 14:35:00 +01:00
Revert "CommandHandler overhaul and PrefixHandler added (#1114)"
This reverts commit 87afd98e02
.
This commit is contained in:
parent
42daf96d20
commit
9e2357bc33
16 changed files with 82 additions and 560 deletions
|
@ -1,6 +0,0 @@
|
||||||
telegram.ext.PrefixHandler
|
|
||||||
===========================
|
|
||||||
|
|
||||||
.. autoclass:: telegram.ext.PrefixHandler
|
|
||||||
:members:
|
|
||||||
:show-inheritance:
|
|
|
@ -25,7 +25,6 @@ Handlers
|
||||||
telegram.ext.inlinequeryhandler
|
telegram.ext.inlinequeryhandler
|
||||||
telegram.ext.messagehandler
|
telegram.ext.messagehandler
|
||||||
telegram.ext.precheckoutqueryhandler
|
telegram.ext.precheckoutqueryhandler
|
||||||
telegram.ext.prefixhandler
|
|
||||||
telegram.ext.regexhandler
|
telegram.ext.regexhandler
|
||||||
telegram.ext.shippingqueryhandler
|
telegram.ext.shippingqueryhandler
|
||||||
telegram.ext.stringcommandhandler
|
telegram.ext.stringcommandhandler
|
||||||
|
|
|
@ -25,7 +25,7 @@ from .jobqueue import JobQueue, Job
|
||||||
from .updater import Updater
|
from .updater import Updater
|
||||||
from .callbackqueryhandler import CallbackQueryHandler
|
from .callbackqueryhandler import CallbackQueryHandler
|
||||||
from .choseninlineresulthandler import ChosenInlineResultHandler
|
from .choseninlineresulthandler import ChosenInlineResultHandler
|
||||||
from .commandhandler import CommandHandler, PrefixHandler
|
from .commandhandler import CommandHandler
|
||||||
from .inlinequeryhandler import InlineQueryHandler
|
from .inlinequeryhandler import InlineQueryHandler
|
||||||
from .messagehandler import MessageHandler
|
from .messagehandler import MessageHandler
|
||||||
from .filters import BaseFilter, Filters
|
from .filters import BaseFilter, Filters
|
||||||
|
@ -44,4 +44,4 @@ __all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
|
||||||
'MessageHandler', 'BaseFilter', 'Filters', 'RegexHandler', 'StringCommandHandler',
|
'MessageHandler', 'BaseFilter', 'Filters', 'RegexHandler', 'StringCommandHandler',
|
||||||
'StringRegexHandler', 'TypeHandler', 'ConversationHandler',
|
'StringRegexHandler', 'TypeHandler', 'ConversationHandler',
|
||||||
'PreCheckoutQueryHandler', 'ShippingQueryHandler', 'MessageQueue', 'DelayQueue',
|
'PreCheckoutQueryHandler', 'ShippingQueryHandler', 'MessageQueue', 'DelayQueue',
|
||||||
'DispatcherHandlerStop', 'run_async', 'CallbackContext', 'PrefixHandler')
|
'DispatcherHandlerStop', 'run_async', 'CallbackContext')
|
||||||
|
|
|
@ -37,9 +37,9 @@ class CallbackContext(object):
|
||||||
regex-supported handler, this will contain the object returned from
|
regex-supported handler, this will contain the object returned from
|
||||||
``re.match(pattern, string)``.
|
``re.match(pattern, string)``.
|
||||||
args (List[:obj:`str`], optional): Arguments passed to a command if the associated update
|
args (List[:obj:`str`], optional): Arguments passed to a command if the associated update
|
||||||
is handled by :class:`telegram.ext.CommandHandler`, :class:`telegram.ext.PrefixHandler`
|
is handled by :class:`telegram.ext.CommandHandler` or
|
||||||
or :class:`telegram.ext.StringCommandHandler`. It contains a list of the words in the
|
:class:`telegram.ext.StringCommandHandler`. It contains a list of the words in the text
|
||||||
text after the command, using any whitespace string as a delimiter.
|
after the command, using any whitespace string as a delimiter.
|
||||||
error (:class:`telegram.TelegramError`, optional): The Telegram error that was raised.
|
error (:class:`telegram.TelegramError`, optional): The Telegram error that was raised.
|
||||||
Only present when passed to a error handler registered with
|
Only present when passed to a error handler registered with
|
||||||
:attr:`telegram.ext.Dispatcher.add_error_handler`.
|
:attr:`telegram.ext.Dispatcher.add_error_handler`.
|
||||||
|
|
|
@ -50,7 +50,7 @@ class CallbackQueryHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class ChosenInlineResultHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,10 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser Public License
|
# You should have received a copy of the GNU Lesser Public License
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
"""This module contains the CommandHandler and PrefixHandler classes."""
|
"""This module contains the CommandHandler class."""
|
||||||
import re
|
|
||||||
|
|
||||||
from future.utils import string_types
|
from future.utils import string_types
|
||||||
|
|
||||||
from telegram import Update, MessageEntity
|
from telegram import Update
|
||||||
from .handler import Handler
|
from .handler import Handler
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,14 +27,11 @@ class CommandHandler(Handler):
|
||||||
"""Handler class to handle Telegram commands.
|
"""Handler class to handle Telegram commands.
|
||||||
|
|
||||||
Commands are Telegram messages that start with ``/``, optionally followed by an ``@`` and the
|
Commands are Telegram messages that start with ``/``, optionally followed by an ``@`` and the
|
||||||
bot's name and/or some additional text. The handler will add a ``list`` to the
|
bot's name and/or some additional text.
|
||||||
:class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings,
|
|
||||||
which is the text following the command split on single or consecutive whitespace characters.
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
|
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
|
||||||
should listen for. Limitations are the same as described here
|
should listen for.
|
||||||
https://core.telegram.org/bots#commands
|
|
||||||
callback (:obj:`callable`): The callback function for this handler.
|
callback (:obj:`callable`): The callback function for this handler.
|
||||||
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
|
filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these
|
||||||
Filters.
|
Filters.
|
||||||
|
@ -55,7 +50,7 @@ class CommandHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
@ -64,8 +59,7 @@ class CommandHandler(Handler):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
|
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
|
||||||
should listen for. Limitations are the same as described here
|
should listen for.
|
||||||
https://core.telegram.org/bots#commands
|
|
||||||
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
callback (:obj:`callable`): The callback function for this handler. Will be called when
|
||||||
:attr:`check_update` has determined that an update should be processed by this handler.
|
:attr:`check_update` has determined that an update should be processed by this handler.
|
||||||
Callback signature for context based API:
|
Callback signature for context based API:
|
||||||
|
@ -102,8 +96,6 @@ class CommandHandler(Handler):
|
||||||
``chat_data`` will be passed to the callback function. Default is ``False``.
|
``chat_data`` will be passed to the callback function. Default is ``False``.
|
||||||
DEPRECATED: Please switch to context based callbacks.
|
DEPRECATED: Please switch to context based callbacks.
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError - when command is too long or has illegal chars.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -127,10 +119,6 @@ class CommandHandler(Handler):
|
||||||
self.command = [command.lower()]
|
self.command = [command.lower()]
|
||||||
else:
|
else:
|
||||||
self.command = [x.lower() for x in command]
|
self.command = [x.lower() for x in command]
|
||||||
for comm in self.command:
|
|
||||||
if not re.match(r'^[\da-z_]{1,32}$', comm):
|
|
||||||
raise ValueError('Command is not a valid bot command')
|
|
||||||
|
|
||||||
self.filters = filters
|
self.filters = filters
|
||||||
self.allow_edited = allow_edited
|
self.allow_edited = allow_edited
|
||||||
self.pass_args = pass_args
|
self.pass_args = pass_args
|
||||||
|
@ -147,21 +135,21 @@ class CommandHandler(Handler):
|
||||||
"""
|
"""
|
||||||
if (isinstance(update, Update) and
|
if (isinstance(update, Update) and
|
||||||
(update.message or update.edited_message and self.allow_edited)):
|
(update.message or update.edited_message and self.allow_edited)):
|
||||||
message = update.effective_message
|
message = update.message or update.edited_message
|
||||||
|
|
||||||
if (message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND and
|
if message.text and message.text.startswith('/') and len(message.text) > 1:
|
||||||
message.entities[0].offset == 0):
|
first_word = message.text_html.split(None, 1)[0]
|
||||||
command = message.text[1:message.entities[0].length]
|
if len(first_word) > 1 and first_word.startswith('/'):
|
||||||
args = message.text.split()[1:]
|
command = first_word[1:].split('@')
|
||||||
command = command.split('@')
|
command.append(
|
||||||
command.append(message.bot.username)
|
message.bot.username) # in case the command was sent without a username
|
||||||
|
|
||||||
if not (command[0].lower() in self.command and
|
if not (command[0].lower() in self.command
|
||||||
command[1].lower() == message.bot.username.lower()):
|
and command[1].lower() == message.bot.username.lower()):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self.filters is None or self.filters(message):
|
if self.filters is None or self.filters(message):
|
||||||
return args
|
return message.text.split()[1:]
|
||||||
|
|
||||||
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
def collect_optional_args(self, dispatcher, update=None, check_result=None):
|
||||||
optional_args = super(CommandHandler, self).collect_optional_args(dispatcher, update)
|
optional_args = super(CommandHandler, self).collect_optional_args(dispatcher, update)
|
||||||
|
@ -171,149 +159,3 @@ class CommandHandler(Handler):
|
||||||
|
|
||||||
def collect_additional_context(self, context, update, dispatcher, check_result):
|
def collect_additional_context(self, context, update, dispatcher, check_result):
|
||||||
context.args = check_result
|
context.args = check_result
|
||||||
|
|
||||||
|
|
||||||
class PrefixHandler(CommandHandler):
|
|
||||||
"""Handler class to handle custom prefix commands
|
|
||||||
|
|
||||||
This is a intermediate handler between :class:`MessageHandler` and :class:`CommandHandler`.
|
|
||||||
It supports configurable commands with the same options as CommandHandler. It will respond to
|
|
||||||
every combination of :attr:`prefix` and :attr:`command`. It will add a ``list`` to the
|
|
||||||
:class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings,
|
|
||||||
which is the text following the command split on single or consecutive whitespace characters.
|
|
||||||
|
|
||||||
Examples::
|
|
||||||
|
|
||||||
Single prefix and command:
|
|
||||||
|
|
||||||
PrefixHandler('!', 'test', callback) will respond to '!test'.
|
|
||||||
|
|
||||||
Multiple prefixes, single command:
|
|
||||||
|
|
||||||
PrefixHandler(['!', '#'], 'test', callback) will respond to '!test' and
|
|
||||||
'#test'.
|
|
||||||
|
|
||||||
Miltiple prefixes and commands:
|
|
||||||
|
|
||||||
PrefixHandler(['!', '#'], ['test', 'help`], callback) will respond to '!test',
|
|
||||||
'#test', '!help' and '#help'.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
prefix (:obj:`str` | List[:obj:`str`]): The prefix(es) that will precede :attr:`command`.
|
|
||||||
command (:obj:`str` | List[:obj:`str`]): The command or list of commands this handler
|
|
||||||
should listen for.
|
|
||||||
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.
|
|
||||||
|
|
||||||
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/vp113 for more info.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
prefix (:obj:`str` | List[:obj:`str`]): The prefix(es) that will precede :attr:`command`.
|
|
||||||
command (:obj:`str` | List[:obj:`str`]): 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)``
|
|
||||||
|
|
||||||
The return value of the callback is usually ignored except for the special case of
|
|
||||||
:class:`telegram.ext.ConversationHandler`.
|
|
||||||
filters (:class:`telegram.ext.BaseFilter`, optional): A filter inheriting from
|
|
||||||
: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 ``False``.
|
|
||||||
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 ``False``
|
|
||||||
DEPRECATED: Please switch to context based callbacks.
|
|
||||||
pass_update_queue (:obj:`bool`, optional): If set to ``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 ``False``.
|
|
||||||
DEPRECATED: Please switch to context based callbacks.
|
|
||||||
pass_job_queue (:obj:`bool`, optional): If set to ``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 ``False``.
|
|
||||||
DEPRECATED: Please switch to context based callbacks.
|
|
||||||
pass_user_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
|
||||||
``user_data`` will be passed to the callback function. Default is ``False``.
|
|
||||||
DEPRECATED: Please switch to context based callbacks.
|
|
||||||
pass_chat_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
|
|
||||||
``chat_data`` will be passed to the callback function. Default is ``False``.
|
|
||||||
DEPRECATED: Please switch to context based callbacks.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
prefix,
|
|
||||||
command,
|
|
||||||
callback,
|
|
||||||
filters=None,
|
|
||||||
allow_edited=False,
|
|
||||||
pass_args=False,
|
|
||||||
pass_update_queue=False,
|
|
||||||
pass_job_queue=False,
|
|
||||||
pass_user_data=False,
|
|
||||||
pass_chat_data=False):
|
|
||||||
|
|
||||||
super(PrefixHandler, self).__init__(
|
|
||||||
'nocommand', callback, filters=filters, allow_edited=allow_edited, 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)
|
|
||||||
|
|
||||||
if isinstance(prefix, string_types):
|
|
||||||
self.prefix = [prefix.lower()]
|
|
||||||
else:
|
|
||||||
self.prefix = prefix
|
|
||||||
if isinstance(command, string_types):
|
|
||||||
self.command = [command.lower()]
|
|
||||||
else:
|
|
||||||
self.command = command
|
|
||||||
self.command = [x.lower() + y.lower() for x in self.prefix for y in self.command]
|
|
||||||
|
|
||||||
def check_update(self, update):
|
|
||||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
update (:class:`telegram.Update`): Incoming telegram update.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`bool`
|
|
||||||
|
|
||||||
"""
|
|
||||||
if (isinstance(update, Update) and
|
|
||||||
(update.message or update.edited_message and self.allow_edited)):
|
|
||||||
message = update.effective_message
|
|
||||||
|
|
||||||
text_list = message.text.split()
|
|
||||||
if text_list[0].lower() not in self.command:
|
|
||||||
return None
|
|
||||||
if self.filters is None or self.filters(message):
|
|
||||||
return text_list[1:]
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ class Handler(object):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class InlineQueryHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ class MessageHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class PreCheckoutQueryHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ class RegexHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ class ShippingQueryHandler(Handler):
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
:attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
|
: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
|
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
|
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``.
|
or in the same chat, it will be the same ``dict``.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
#
|
||||||
# A library that provides a Python interface to the Telegram Bot API
|
# A library that provides a Python interface to the Telegram Bot API
|
||||||
# Copyright (C) 2015-2018
|
# Copyright (C) 2015-2018
|
||||||
|
@ -22,9 +21,8 @@ from queue import Queue
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from telegram import (Message, Update, Chat, Bot, User, CallbackQuery, InlineQuery,
|
from telegram import (Message, Update, Chat, Bot, User, CallbackQuery, InlineQuery,
|
||||||
ChosenInlineResult, ShippingQuery, PreCheckoutQuery, MessageEntity)
|
ChosenInlineResult, ShippingQuery, PreCheckoutQuery)
|
||||||
from telegram.ext import CommandHandler, Filters, BaseFilter, CallbackContext, JobQueue, \
|
from telegram.ext import CommandHandler, Filters, BaseFilter, CallbackContext, JobQueue
|
||||||
PrefixHandler
|
|
||||||
|
|
||||||
message = Message(1, User(1, '', False), None, Chat(1, ''), text='test')
|
message = Message(1, User(1, '', False), None, Chat(1, ''), text='test')
|
||||||
|
|
||||||
|
@ -51,15 +49,7 @@ def false_update(request):
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def message(bot):
|
def message(bot):
|
||||||
return Message(message_id=1,
|
return Message(1, User(1, '', False), None, Chat(1, ''), bot=bot)
|
||||||
from_user=User(id=1, first_name='', is_bot=False),
|
|
||||||
date=None,
|
|
||||||
chat=Chat(id=1, type=''),
|
|
||||||
message='/test',
|
|
||||||
bot=bot,
|
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0,
|
|
||||||
length=len('/test'))])
|
|
||||||
|
|
||||||
|
|
||||||
class TestCommandHandler(object):
|
class TestCommandHandler(object):
|
||||||
|
@ -127,26 +117,13 @@ class TestCommandHandler(object):
|
||||||
check = handler.check_update(Update(0, message))
|
check = handler.check_update(Update(0, message))
|
||||||
assert check is None or check is False
|
assert check is None or check is False
|
||||||
|
|
||||||
message.entities = []
|
|
||||||
message.text = '/test'
|
|
||||||
check = handler.check_update(Update(0, message))
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('command',
|
|
||||||
['way_too_longcommand1234567yes_way_toooooooLong', 'ïñválídletters',
|
|
||||||
'invalid #&* chars'],
|
|
||||||
ids=['too long', 'invalid letter', 'invalid characters'])
|
|
||||||
def test_invalid_commands(self, command):
|
|
||||||
with pytest.raises(ValueError, match='not a valid bot command'):
|
|
||||||
CommandHandler(command, self.callback_basic)
|
|
||||||
|
|
||||||
def test_command_list(self, message):
|
def test_command_list(self, message):
|
||||||
handler = CommandHandler(['test', 'star'], self.callback_basic)
|
handler = CommandHandler(['test', 'start'], self.callback_basic)
|
||||||
|
|
||||||
message.text = '/test'
|
message.text = '/test'
|
||||||
check = handler.check_update(Update(0, message))
|
check = handler.check_update(Update(0, message))
|
||||||
|
|
||||||
message.text = '/star'
|
message.text = '/start'
|
||||||
check = handler.check_update(Update(0, message))
|
check = handler.check_update(Update(0, message))
|
||||||
|
|
||||||
message.text = '/stop'
|
message.text = '/stop'
|
||||||
|
@ -160,14 +137,11 @@ class TestCommandHandler(object):
|
||||||
message.text = '/test'
|
message.text = '/test'
|
||||||
check = handler.check_update(Update(0, message))
|
check = handler.check_update(Update(0, message))
|
||||||
assert check is not None and check is not False
|
assert check is not None and check is not False
|
||||||
|
|
||||||
check = handler.check_update(Update(0, edited_message=message))
|
check = handler.check_update(Update(0, edited_message=message))
|
||||||
assert check is None or check is False
|
assert check is None or check is False
|
||||||
|
|
||||||
handler.allow_edited = True
|
handler.allow_edited = True
|
||||||
check = handler.check_update(Update(0, message))
|
check = handler.check_update(Update(0, message))
|
||||||
assert check is not None and check is not False
|
assert check is not None and check is not False
|
||||||
|
|
||||||
check = handler.check_update(Update(0, edited_message=message))
|
check = handler.check_update(Update(0, edited_message=message))
|
||||||
assert check is not None and check is not False
|
assert check is not None and check is not False
|
||||||
|
|
||||||
|
@ -175,13 +149,11 @@ class TestCommandHandler(object):
|
||||||
handler = CommandHandler('test', self.callback_basic)
|
handler = CommandHandler('test', self.callback_basic)
|
||||||
|
|
||||||
message.text = '/test@{}'.format(message.bot.username)
|
message.text = '/test@{}'.format(message.bot.username)
|
||||||
message.entities[0].length = len(message.text)
|
|
||||||
check = handler.check_update(Update(0, message))
|
check = handler.check_update(Update(0, message))
|
||||||
assert check is not None and check is not False
|
assert check is not None and check is not False
|
||||||
|
|
||||||
message.text = '/test@otherbot'
|
message.text = '/test@otherbot'
|
||||||
check = handler.check_update(Update(0, message))
|
assert not handler.check_update(Update(0, message))
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
def test_with_filter(self, message):
|
def test_with_filter(self, message):
|
||||||
handler = CommandHandler('test', self.callback_basic, Filters.group)
|
handler = CommandHandler('test', self.callback_basic, Filters.group)
|
||||||
|
@ -205,18 +177,16 @@ class TestCommandHandler(object):
|
||||||
|
|
||||||
self.test_flag = False
|
self.test_flag = False
|
||||||
message.text = '/test@{}'.format(message.bot.username)
|
message.text = '/test@{}'.format(message.bot.username)
|
||||||
message.entities[0].length = len(message.text)
|
|
||||||
dp.process_update(Update(0, message=message))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
self.test_flag = False
|
|
||||||
message.text = '/test@{} one two'.format(message.bot.username)
|
|
||||||
dp.process_update(Update(0, message=message))
|
dp.process_update(Update(0, message=message))
|
||||||
assert self.test_flag
|
assert self.test_flag
|
||||||
|
|
||||||
self.test_flag = False
|
self.test_flag = False
|
||||||
message.text = '/test one two'
|
message.text = '/test one two'
|
||||||
message.entities[0].length = len('/test')
|
dp.process_update(Update(0, message=message))
|
||||||
|
assert self.test_flag
|
||||||
|
|
||||||
|
self.test_flag = False
|
||||||
|
message.text = '/test@{} one two'.format(message.bot.username)
|
||||||
dp.process_update(Update(0, message=message))
|
dp.process_update(Update(0, message=message))
|
||||||
assert self.test_flag
|
assert self.test_flag
|
||||||
|
|
||||||
|
@ -227,10 +197,31 @@ class TestCommandHandler(object):
|
||||||
message.text = '/test\nfoobar'
|
message.text = '/test\nfoobar'
|
||||||
check = handler.check_update(Update(0, message))
|
check = handler.check_update(Update(0, message))
|
||||||
assert check is not None and check is not False
|
assert check is not None and check is not False
|
||||||
|
|
||||||
dp.process_update(Update(0, message))
|
dp.process_update(Update(0, message))
|
||||||
assert self.test_flag
|
assert self.test_flag
|
||||||
|
|
||||||
|
def test_single_char(self, dp, message):
|
||||||
|
# Regression test for https://github.com/python-telegram-bot/python-telegram-bot/issues/871
|
||||||
|
handler = CommandHandler('test', self.callback_basic)
|
||||||
|
dp.add_handler(handler)
|
||||||
|
|
||||||
|
message.text = 'a'
|
||||||
|
check = handler.check_update(Update(0, message))
|
||||||
|
assert check is None or check is False
|
||||||
|
|
||||||
|
def test_single_slash(self, dp, message):
|
||||||
|
# Regression test for https://github.com/python-telegram-bot/python-telegram-bot/issues/871
|
||||||
|
handler = CommandHandler('test', self.callback_basic)
|
||||||
|
dp.add_handler(handler)
|
||||||
|
|
||||||
|
message.text = '/'
|
||||||
|
check = handler.check_update(Update(0, message))
|
||||||
|
assert check is None or check is False
|
||||||
|
|
||||||
|
message.text = '/ test'
|
||||||
|
check = handler.check_update(Update(0, message))
|
||||||
|
assert check is None or check is False
|
||||||
|
|
||||||
def test_pass_user_or_chat_data(self, dp, message):
|
def test_pass_user_or_chat_data(self, dp, message):
|
||||||
handler = CommandHandler('test', self.callback_data_1,
|
handler = CommandHandler('test', self.callback_data_1,
|
||||||
pass_user_data=True)
|
pass_user_data=True)
|
||||||
|
@ -304,9 +295,9 @@ class TestCommandHandler(object):
|
||||||
|
|
||||||
test_filter = TestFilter()
|
test_filter = TestFilter()
|
||||||
|
|
||||||
handler = CommandHandler('test', self.callback_basic,
|
handler = CommandHandler('foo', self.callback_basic,
|
||||||
filters=test_filter)
|
filters=test_filter)
|
||||||
message.text = '/star'
|
message.text = '/bar'
|
||||||
|
|
||||||
check = handler.check_update(Update(0, message=message))
|
check = handler.check_update(Update(0, message=message))
|
||||||
assert check is None or check is False
|
assert check is None or check is False
|
||||||
|
@ -332,241 +323,3 @@ class TestCommandHandler(object):
|
||||||
message.text = '/test one two'
|
message.text = '/test one two'
|
||||||
cdp.process_update(Update(0, message))
|
cdp.process_update(Update(0, message))
|
||||||
assert self.test_flag
|
assert self.test_flag
|
||||||
|
|
||||||
|
|
||||||
par = ['!help', '!test', '#help', '#test', 'mytrig-help', 'mytrig-test']
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function', params=par)
|
|
||||||
def prefixmessage(bot, request):
|
|
||||||
return Message(message_id=1,
|
|
||||||
from_user=User(id=1, first_name='', is_bot=False),
|
|
||||||
date=None,
|
|
||||||
chat=Chat(id=1, type=''),
|
|
||||||
text=request.param,
|
|
||||||
bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
class TestPrefixHandler(object):
|
|
||||||
test_flag = False
|
|
||||||
|
|
||||||
@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 ch_callback_args(self, bot, update, args):
|
|
||||||
if update.message.text in par:
|
|
||||||
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) 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(update.message, Message))
|
|
||||||
|
|
||||||
def callback_context_args(self, update, context):
|
|
||||||
self.test_flag = context.args == ['one', 'two']
|
|
||||||
|
|
||||||
def test_basic(self, dp, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_basic)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
|
|
||||||
dp.process_update(Update(0, prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
prefixmessage.text = 'test'
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
prefixmessage.text = '#nocom'
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
message.text = 'not !test at start'
|
|
||||||
check = handler.check_update(Update(0, message))
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
def test_single_prefix_single_command(self, prefixmessage):
|
|
||||||
handler = PrefixHandler('!', 'test', self.callback_basic)
|
|
||||||
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
if prefixmessage.text in ['!test']:
|
|
||||||
assert check is not None and check is not False
|
|
||||||
else:
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
def test_single_prefix_multi_command(self, prefixmessage):
|
|
||||||
handler = PrefixHandler('!', ['test', 'help'], self.callback_basic)
|
|
||||||
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
if prefixmessage.text in ['!test', '!help']:
|
|
||||||
assert check is not None and check is not False
|
|
||||||
else:
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
def test_multi_prefix_single_command(self, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#'], 'test', self.callback_basic)
|
|
||||||
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
if prefixmessage.text in ['!test', '#test']:
|
|
||||||
assert check is not None and check is not False
|
|
||||||
else:
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
def test_edited(self, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_basic)
|
|
||||||
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
assert check is not None and check is not False
|
|
||||||
|
|
||||||
check = handler.check_update(Update(0, edited_message=prefixmessage))
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
handler.allow_edited = True
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
assert check is not None and check is not False
|
|
||||||
|
|
||||||
check = handler.check_update(Update(0, edited_message=prefixmessage))
|
|
||||||
assert check is not None and check is not False
|
|
||||||
|
|
||||||
def test_with_filter(self, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_basic,
|
|
||||||
filters=Filters.group)
|
|
||||||
|
|
||||||
prefixmessage.chat = Chat(-23, 'group')
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
assert check is not None and check is not False
|
|
||||||
|
|
||||||
prefixmessage.chat = Chat(23, 'private')
|
|
||||||
check = handler.check_update(Update(0, prefixmessage))
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
def test_pass_args(self, dp, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.ch_callback_args,
|
|
||||||
pass_args=True)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
self.test_flag = False
|
|
||||||
prefixmessage.text += ' one two'
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
def test_pass_user_or_chat_data(self, dp, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_data_1,
|
|
||||||
pass_user_data=True)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
dp.remove_handler(handler)
|
|
||||||
self.test_flag = False
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_data_1,
|
|
||||||
pass_chat_data=True)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
dp.remove_handler(handler)
|
|
||||||
self.test_flag = False
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_data_2,
|
|
||||||
pass_chat_data=True, pass_user_data=True)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
def test_pass_job_or_update_queue(self, dp, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_queue_1,
|
|
||||||
pass_job_queue=True)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
dp.remove_handler(handler)
|
|
||||||
self.test_flag = False
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_queue_1,
|
|
||||||
pass_update_queue=True)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
dp.remove_handler(handler)
|
|
||||||
self.test_flag = False
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_queue_2,
|
|
||||||
pass_job_queue=True, pass_update_queue=True)
|
|
||||||
dp.add_handler(handler)
|
|
||||||
dp.process_update(Update(0, message=prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
def test_other_update_types(self, false_update):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_basic)
|
|
||||||
check = handler.check_update(false_update)
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
def test_filters_for_wrong_command(self, prefixmessage):
|
|
||||||
"""Filters should not be executed if the command does not match the handler"""
|
|
||||||
|
|
||||||
class TestFilter(BaseFilter):
|
|
||||||
def __init__(self):
|
|
||||||
self.tested = False
|
|
||||||
|
|
||||||
def filter(self, message):
|
|
||||||
self.tested = True
|
|
||||||
|
|
||||||
test_filter = TestFilter()
|
|
||||||
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_basic,
|
|
||||||
filters=test_filter)
|
|
||||||
|
|
||||||
prefixmessage.text = '/star'
|
|
||||||
|
|
||||||
check = handler.check_update(Update(0, message=prefixmessage))
|
|
||||||
assert check is None or check is False
|
|
||||||
|
|
||||||
assert not test_filter.tested
|
|
||||||
|
|
||||||
def test_context(self, cdp, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'], self.callback_context)
|
|
||||||
cdp.add_handler(handler)
|
|
||||||
|
|
||||||
cdp.process_update(Update(0, prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
||||||
def test_context_args(self, cdp, prefixmessage):
|
|
||||||
handler = PrefixHandler(['!', '#', 'mytrig-'], ['help', 'test'],
|
|
||||||
self.callback_context_args)
|
|
||||||
cdp.add_handler(handler)
|
|
||||||
|
|
||||||
cdp.process_update(Update(0, prefixmessage))
|
|
||||||
assert not self.test_flag
|
|
||||||
|
|
||||||
prefixmessage.text += ' one two'
|
|
||||||
cdp.process_update(Update(0, prefixmessage))
|
|
||||||
assert self.test_flag
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ from time import sleep
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from telegram import (CallbackQuery, Chat, ChosenInlineResult, InlineQuery, Message,
|
from telegram import (CallbackQuery, Chat, ChosenInlineResult, InlineQuery, Message,
|
||||||
PreCheckoutQuery, ShippingQuery, Update, User, MessageEntity)
|
PreCheckoutQuery, ShippingQuery, Update, User)
|
||||||
from telegram.ext import (ConversationHandler, CommandHandler, CallbackQueryHandler)
|
from telegram.ext import (ConversationHandler, CommandHandler, CallbackQueryHandler)
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,28 +103,22 @@ class TestConversationHandler(object):
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
# User one, starts the state machine.
|
# User one, starts the state machine.
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert self.current_state[user1.id] == self.THIRSTY
|
assert self.current_state[user1.id] == self.THIRSTY
|
||||||
|
|
||||||
# The user is thirsty and wants to brew coffee.
|
# The user is thirsty and wants to brew coffee.
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert self.current_state[user1.id] == self.BREWING
|
assert self.current_state[user1.id] == self.BREWING
|
||||||
|
|
||||||
# Lets see if an invalid command makes sure, no state is changed.
|
# Lets see if an invalid command makes sure, no state is changed.
|
||||||
message.text = '/nothing'
|
message.text = '/nothing'
|
||||||
message.entities[0].length = len('/nothing')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert self.current_state[user1.id] == self.BREWING
|
assert self.current_state[user1.id] == self.BREWING
|
||||||
|
|
||||||
# Lets see if the state machine still works by pouring coffee.
|
# Lets see if the state machine still works by pouring coffee.
|
||||||
message.text = '/pourCoffee'
|
message.text = '/pourCoffee'
|
||||||
message.entities[0].length = len('/pourCoffee')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert self.current_state[user1.id] == self.DRINKING
|
assert self.current_state[user1.id] == self.DRINKING
|
||||||
|
|
||||||
|
@ -140,19 +134,13 @@ class TestConversationHandler(object):
|
||||||
fallbacks=self.fallbacks)
|
fallbacks=self.fallbacks)
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
message.text = '/pourCoffee'
|
message.text = '/pourCoffee'
|
||||||
message.entities[0].length = len('/pourCoffee')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
message.text = '/end'
|
message.text = '/end'
|
||||||
message.entities[0].length = len('/end')
|
|
||||||
with caplog.at_level(logging.ERROR):
|
with caplog.at_level(logging.ERROR):
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert len(caplog.records) == 0
|
assert len(caplog.records) == 0
|
||||||
|
@ -166,29 +154,23 @@ class TestConversationHandler(object):
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
# first check if fallback will not trigger start when not started
|
# first check if fallback will not trigger start when not started
|
||||||
message = Message(0, user1, None, self.group, text='/eat',
|
message = Message(0, user1, None, self.group, text='/eat', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/eat'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
self.current_state[user1.id]
|
self.current_state[user1.id]
|
||||||
|
|
||||||
# User starts the state machine.
|
# User starts the state machine.
|
||||||
message.text = '/start'
|
message.text = '/start'
|
||||||
message.entities[0].length = len('/start')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert self.current_state[user1.id] == self.THIRSTY
|
assert self.current_state[user1.id] == self.THIRSTY
|
||||||
|
|
||||||
# The user is thirsty and wants to brew coffee.
|
# The user is thirsty and wants to brew coffee.
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert self.current_state[user1.id] == self.BREWING
|
assert self.current_state[user1.id] == self.BREWING
|
||||||
|
|
||||||
# Now a fallback command is issued
|
# Now a fallback command is issued
|
||||||
message.text = '/eat'
|
message.text = '/eat'
|
||||||
message.entities[0].length = len('/eat')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert self.current_state[user1.id] == self.THIRSTY
|
assert self.current_state[user1.id] == self.THIRSTY
|
||||||
|
|
||||||
|
@ -201,22 +183,17 @@ class TestConversationHandler(object):
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
# User one, starts the state machine.
|
# User one, starts the state machine.
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
|
|
||||||
# The user is thirsty and wants to brew coffee.
|
# The user is thirsty and wants to brew coffee.
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
|
|
||||||
# Let's now verify that for another user, who did not start yet,
|
# Let's now verify that for another user, who did not start yet,
|
||||||
# the state will be changed because they are in the same group.
|
# the state will be changed because they are in the same group.
|
||||||
message.from_user = user2
|
message.from_user = user2
|
||||||
message.text = '/pourCoffee'
|
message.text = '/pourCoffee'
|
||||||
message.entities[0].length = len('/pourCoffee')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
|
|
||||||
assert handler.conversations[(self.group.id,)] == self.DRINKING
|
assert handler.conversations[(self.group.id,)] == self.DRINKING
|
||||||
|
@ -230,22 +207,17 @@ class TestConversationHandler(object):
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
# User one, starts the state machine.
|
# User one, starts the state machine.
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
|
|
||||||
# The user is thirsty and wants to brew coffee.
|
# The user is thirsty and wants to brew coffee.
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
|
|
||||||
# Let's now verify that for the same user in a different group, the state will still be
|
# Let's now verify that for the same user in a different group, the state will still be
|
||||||
# updated
|
# updated
|
||||||
message.chat = self.second_group
|
message.chat = self.second_group
|
||||||
message.text = '/pourCoffee'
|
message.text = '/pourCoffee'
|
||||||
message.entities[0].length = len('/pourCoffee')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
|
|
||||||
assert handler.conversations[(user1.id,)] == self.DRINKING
|
assert handler.conversations[(user1.id,)] == self.DRINKING
|
||||||
|
@ -294,10 +266,7 @@ class TestConversationHandler(object):
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
# User starts the state machine and immediately ends it.
|
# User starts the state machine and immediately ends it.
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert len(handler.conversations) == 0
|
assert len(handler.conversations) == 0
|
||||||
|
|
||||||
|
@ -311,17 +280,13 @@ class TestConversationHandler(object):
|
||||||
|
|
||||||
# User starts the state machine with an async function that immediately ends the
|
# User starts the state machine with an async function that immediately ends the
|
||||||
# conversation. Async results are resolved when the users state is queried next time.
|
# conversation. Async results are resolved when the users state is queried next time.
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.update_queue.put(Update(update_id=0, message=message))
|
dp.update_queue.put(Update(update_id=0, message=message))
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
# Assert that the Promise has been accepted as the new state
|
# Assert that the Promise has been accepted as the new state
|
||||||
assert len(handler.conversations) == 1
|
assert len(handler.conversations) == 1
|
||||||
|
|
||||||
message.text = 'resolve promise pls'
|
message.text = 'resolve promise pls'
|
||||||
message.entities[0].length = len('resolve promise pls')
|
|
||||||
dp.update_queue.put(Update(update_id=0, message=message))
|
dp.update_queue.put(Update(update_id=0, message=message))
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
# Assert that the Promise has been resolved and the conversation ended.
|
# Assert that the Promise has been resolved and the conversation ended.
|
||||||
|
@ -364,10 +329,7 @@ class TestConversationHandler(object):
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
# Start state machine, then reach timeout
|
# Start state machine, then reach timeout
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
|
@ -378,7 +340,6 @@ class TestConversationHandler(object):
|
||||||
dp.process_update(Update(update_id=1, message=message))
|
dp.process_update(Update(update_id=1, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
dp.job_queue.tick()
|
dp.job_queue.tick()
|
||||||
dp.process_update(Update(update_id=2, message=message))
|
dp.process_update(Update(update_id=2, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
|
assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
|
||||||
|
@ -398,24 +359,19 @@ class TestConversationHandler(object):
|
||||||
# t=.6 /pourCoffee (timeout=1.1)
|
# t=.6 /pourCoffee (timeout=1.1)
|
||||||
# t=.75 second timeout
|
# t=.75 second timeout
|
||||||
# t=1.1 actual timeout
|
# t=1.1 actual timeout
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0, length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
||||||
sleep(0.25) # t=.25
|
sleep(0.25) # t=.25
|
||||||
dp.job_queue.tick()
|
dp.job_queue.tick()
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
|
assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
|
||||||
sleep(0.35) # t=.6
|
sleep(0.35) # t=.6
|
||||||
dp.job_queue.tick()
|
dp.job_queue.tick()
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
|
assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
|
||||||
message.text = '/pourCoffee'
|
message.text = '/pourCoffee'
|
||||||
message.entities[0].length = len('/pourCoffee')
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.DRINKING
|
assert handler.conversations.get((self.group.id, user1.id)) == self.DRINKING
|
||||||
sleep(.4) # t=1
|
sleep(.4) # t=1
|
||||||
|
@ -431,21 +387,15 @@ class TestConversationHandler(object):
|
||||||
dp.add_handler(handler)
|
dp.add_handler(handler)
|
||||||
|
|
||||||
# Start state machine, do something as second user, then reach timeout
|
# Start state machine, do something as second user, then reach timeout
|
||||||
message = Message(0, user1, None, self.group, text='/start',
|
message = Message(0, user1, None, self.group, text='/start', bot=bot)
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0,
|
|
||||||
length=len('/start'))],
|
|
||||||
bot=bot)
|
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
|
||||||
message.text = '/brew'
|
message.text = '/brew'
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
message.entities[0].length = len('/brew')
|
|
||||||
message.from_user = user2
|
message.from_user = user2
|
||||||
dp.job_queue.tick()
|
dp.job_queue.tick()
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user2.id)) is None
|
assert handler.conversations.get((self.group.id, user2.id)) is None
|
||||||
message.text = '/start'
|
message.text = '/start'
|
||||||
message.entities[0].length = len('/start')
|
|
||||||
dp.job_queue.tick()
|
dp.job_queue.tick()
|
||||||
dp.process_update(Update(update_id=0, message=message))
|
dp.process_update(Update(update_id=0, message=message))
|
||||||
assert handler.conversations.get((self.group.id, user2.id)) == self.THIRSTY
|
assert handler.conversations.get((self.group.id, user2.id)) == self.THIRSTY
|
||||||
|
|
|
@ -23,7 +23,7 @@ from time import sleep
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from telegram import TelegramError, Message, User, Chat, Update, Bot, MessageEntity
|
from telegram import TelegramError, Message, User, Chat, Update, Bot
|
||||||
from telegram.ext import MessageHandler, Filters, CommandHandler, CallbackContext, JobQueue
|
from telegram.ext import MessageHandler, Filters, CommandHandler, CallbackContext, JobQueue
|
||||||
from telegram.ext.dispatcher import run_async, Dispatcher, DispatcherHandlerStop
|
from telegram.ext.dispatcher import run_async, Dispatcher, DispatcherHandlerStop
|
||||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||||
|
@ -227,11 +227,7 @@ class TestDispatcher(object):
|
||||||
passed.append('error')
|
passed.append('error')
|
||||||
passed.append(e)
|
passed.append(e)
|
||||||
|
|
||||||
update = Update(1, message=Message(1, None, None, None, text='/start',
|
update = Update(1, message=Message(1, None, None, None, text='/start', bot=bot))
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0,
|
|
||||||
length=len('/start'))],
|
|
||||||
bot=bot))
|
|
||||||
|
|
||||||
# If Stop raised handlers in other groups should not be called.
|
# If Stop raised handlers in other groups should not be called.
|
||||||
passed = []
|
passed = []
|
||||||
|
@ -258,11 +254,7 @@ class TestDispatcher(object):
|
||||||
passed.append('error')
|
passed.append('error')
|
||||||
passed.append(e)
|
passed.append(e)
|
||||||
|
|
||||||
update = Update(1, message=Message(1, None, None, None, text='/start',
|
update = Update(1, message=Message(1, None, None, None, text='/start', bot=bot))
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0,
|
|
||||||
length=len('/start'))],
|
|
||||||
bot=bot))
|
|
||||||
|
|
||||||
# If an unhandled exception was caught, no further handlers from the same group should be
|
# If an unhandled exception was caught, no further handlers from the same group should be
|
||||||
# called.
|
# called.
|
||||||
|
@ -292,11 +284,7 @@ class TestDispatcher(object):
|
||||||
passed.append('error')
|
passed.append('error')
|
||||||
passed.append(e)
|
passed.append(e)
|
||||||
|
|
||||||
update = Update(1, message=Message(1, None, None, None, text='/start',
|
update = Update(1, message=Message(1, None, None, None, text='/start', bot=bot))
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0,
|
|
||||||
length=len('/start'))],
|
|
||||||
bot=bot))
|
|
||||||
|
|
||||||
# If a TelegramException was caught, an error handler should be called and no further
|
# If a TelegramException was caught, an error handler should be called and no further
|
||||||
# handlers from the same group should be called.
|
# handlers from the same group should be called.
|
||||||
|
@ -327,11 +315,7 @@ class TestDispatcher(object):
|
||||||
passed.append(e)
|
passed.append(e)
|
||||||
raise DispatcherHandlerStop
|
raise DispatcherHandlerStop
|
||||||
|
|
||||||
update = Update(1, message=Message(1, None, None, None, text='/start',
|
update = Update(1, message=Message(1, None, None, None, text='/start', bot=bot))
|
||||||
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND,
|
|
||||||
offset=0,
|
|
||||||
length=len('/start'))],
|
|
||||||
bot=bot))
|
|
||||||
|
|
||||||
# If a TelegramException was caught, an error handler should be called and no further
|
# If a TelegramException was caught, an error handler should be called and no further
|
||||||
# handlers from the same group should be called.
|
# handlers from the same group should be called.
|
||||||
|
|
Loading…
Reference in a new issue