python-telegram-bot/telegram/ext/_conversationhandler.py

743 lines
31 KiB
Python
Raw Normal View History

#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
2022-01-03 08:15:18 +01:00
# 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/].
# pylint: disable=no-self-use
2017-09-01 08:43:08 +02:00
"""This module contains the ConversationHandler."""
import logging
import functools
import datetime
from threading import Lock
from typing import ( # pylint: disable=unused-import # for the "Any" import
TYPE_CHECKING,
Dict,
List,
NoReturn,
Optional,
Union,
Tuple,
cast,
ClassVar,
Any,
)
from telegram import Update
from telegram.ext import (
BasePersistence,
CallbackContext,
CallbackQueryHandler,
ChosenInlineResultHandler,
DispatcherHandlerStop,
Handler,
InlineQueryHandler,
)
from telegram._utils.warnings import warn
from telegram.ext._utils.promise import Promise
from telegram.ext._utils.types import ConversationDict
from telegram.ext._utils.types import CCT
2020-10-06 19:28:40 +02:00
if TYPE_CHECKING:
from telegram.ext import Dispatcher, Job, JobQueue
2020-10-06 19:28:40 +02:00
CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]]
class _ConversationTimeoutContext:
__slots__ = ('conversation_key', 'update', 'dispatcher', 'callback_context')
def __init__(
self,
conversation_key: Tuple[int, ...],
update: Update,
dispatcher: 'Dispatcher[Any, CCT, Any, Any, Any, JobQueue, Any]',
2021-08-29 18:15:04 +02:00
callback_context: CallbackContext,
):
self.conversation_key = conversation_key
self.update = update
self.dispatcher = dispatcher
self.callback_context = callback_context
class ConversationHandler(Handler[Update, CCT]):
"""
A handler to hold a conversation with a single or multiple users through Telegram updates by
managing four collections of other handlers.
Note:
``ConversationHandler`` will only accept updates that are (subclass-)instances of
:class:`telegram.Update`. This is, because depending on the :attr:`per_user` and
:attr:`per_chat` ``ConversationHandler`` relies on
:attr:`telegram.Update.effective_user` and/or :attr:`telegram.Update.effective_chat` in
order to determine which conversation an update should belong to. For ``per_message=True``,
``ConversationHandler`` uses ``update.callback_query.message.message_id`` when
``per_chat=True`` and ``update.callback_query.inline_message_id`` when ``per_chat=False``.
For a more detailed explanation, please see our `FAQ`_.
Finally, ``ConversationHandler``, does *not* handle (edited) channel posts.
.. _`FAQ`: https://git.io/JtcyU
The first collection, a ``list`` named :attr:`entry_points`, is used to initiate the
conversation, for example with a :class:`telegram.ext.CommandHandler` or
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
:class:`telegram.ext.MessageHandler`.
The second collection, a ``dict`` named :attr:`states`, contains the different conversation
steps and one or more associated handlers that should be used if the user sends a message when
the conversation with them is currently in that state. Here you can also define a state for
:attr:`TIMEOUT` to define the behavior when :attr:`conversation_timeout` is exceeded, and a
state for :attr:`WAITING` to define behavior when a new update is received while the previous
``@run_async`` decorated handler is not finished.
The third collection, a ``list`` named :attr:`fallbacks`, is used if the user is currently in a
conversation but the state has either no associated handler or the handler that is associated
to the state is inappropriate for the update, for example if the update contains a command, but
a regular text message is expected. You could use this for a ``/cancel`` command or to let the
user know their message was not recognized.
To change the state of conversation, the callback function of a handler must return the new
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
state after responding to the user. If it does not return anything (returning :obj:`None` by
default), the state will not change. If an entry point callback function returns :obj:`None`,
the conversation ends immediately after the execution of this callback function.
To end the conversation, the callback function must return :attr:`END` or ``-1``. To
handle the conversation timeout, use handler :attr:`TIMEOUT` or ``-2``.
Finally, :class:`telegram.ext.DispatcherHandlerStop` can be used in conversations as described
in the corresponding documentation.
Note:
In each of the described collections of handlers, a handler may in turn be a
:class:`ConversationHandler`. In that case, the nested :class:`ConversationHandler` should
have the attribute :attr:`map_to_parent` which allows to return to the parent conversation
at specified states within the nested conversation.
Note that the keys in :attr:`map_to_parent` must not appear as keys in :attr:`states`
attribute or else the latter will be ignored. You may map :attr:`END` to one of the parents
states to continue the parent conversation after this has ended or even map a state to
:attr:`END` to end the *parent* conversation from within the nested one. For an example on
nested :class:`ConversationHandler` s, see our `examples`_.
.. _`examples`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples
Args:
entry_points (List[:class:`telegram.ext.Handler`]): A list of ``Handler`` objects that can
trigger the start of the conversation. The first handler which :attr:`check_update`
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
method returns :obj:`True` will be used. If all return :obj:`False`, the update is not
handled.
states (Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]): A :obj:`dict` that
defines the different states of conversation a user can be in and one or more
associated ``Handler`` objects that should be used in that state. The first handler
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
which :attr:`check_update` method returns :obj:`True` will be used.
fallbacks (List[:class:`telegram.ext.Handler`]): A list of handlers that might be used if
the user is in a conversation, but every handler for their current state returned
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
:obj:`False` on :attr:`check_update`. The first handler which :attr:`check_update`
method returns :obj:`True` will be used. If all return :obj:`False`, the update is not
handled.
allow_reentry (:obj:`bool`, optional): If set to :obj:`True`, a user that is currently in a
conversation can restart the conversation by triggering one of the entry points.
per_chat (:obj:`bool`, optional): If the conversationkey should contain the Chat's ID.
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
Default is :obj:`True`.
per_user (:obj:`bool`, optional): If the conversationkey should contain the User's ID.
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
Default is :obj:`True`.
per_message (:obj:`bool`, optional): If the conversationkey should contain the Message's
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
ID. Default is :obj:`False`.
conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`, optional): When this
handler is inactive more than this timeout (in seconds), it will be automatically
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
ended. If this value is 0 or :obj:`None` (default), there will be no timeout. The last
received update and the corresponding ``context`` will be handled by ALL the handler's
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
who's :attr:`check_update` method returns :obj:`True` that are in the state
:attr:`ConversationHandler.TIMEOUT`.
Note:
Using `conversation_timeout` with nested conversations is currently not
supported. You can still try to use it, but it will likely behave differently
from what you expect.
name (:obj:`str`, optional): The name for this conversationhandler. Required for
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
persistence.
persistent (:obj:`bool`, optional): If the conversations dict for this handler should be
saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater`
map_to_parent (Dict[:obj:`object`, :obj:`object`], optional): A :obj:`dict` that can be
used to instruct a nested conversationhandler to transition into a mapped state on
its parent conversationhandler in place of a specified nested state.
run_async (:obj:`bool`, optional): Pass :obj:`True` to *override* the
:attr:`Handler.run_async` setting of all handlers (in :attr:`entry_points`,
:attr:`states` and :attr:`fallbacks`).
Note:
If set to :obj:`True`, you should not pass a handler instance, that needs to be
run synchronously in another context.
.. versionadded:: 13.2
Raises:
ValueError
Attributes:
persistent (:obj:`bool`): Optional. If the conversations dict for this handler should be
saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater`
run_async (:obj:`bool`): If :obj:`True`, will override the
:attr:`Handler.run_async` setting of all internal handlers on initialization.
.. versionadded:: 13.2
2017-09-01 08:43:08 +02:00
"""
__slots__ = (
'_entry_points',
'_states',
'_fallbacks',
'_allow_reentry',
'_per_user',
'_per_chat',
'_per_message',
'_conversation_timeout',
'_name',
'persistent',
'_persistence',
'_map_to_parent',
'timeout_jobs',
'_timeout_jobs_lock',
'_conversations',
'_conversations_lock',
'logger',
)
END: ClassVar[int] = -1
""":obj:`int`: Used as a constant to return when a conversation is ended."""
TIMEOUT: ClassVar[int] = -2
""":obj:`int`: Used as a constant to handle state when a conversation is timed out."""
WAITING: ClassVar[int] = -3
""":obj:`int`: Used as a constant to handle state when a conversation is still waiting on the
previous ``@run_sync`` decorated running handler to finish."""
# pylint: disable=super-init-not-called
def __init__(
self,
entry_points: List[Handler[Update, CCT]],
states: Dict[object, List[Handler[Update, CCT]]],
fallbacks: List[Handler[Update, CCT]],
allow_reentry: bool = False,
per_chat: bool = True,
per_user: bool = True,
per_message: bool = False,
conversation_timeout: Union[float, datetime.timedelta] = None,
name: str = None,
persistent: bool = False,
map_to_parent: Dict[object, object] = None,
run_async: bool = False,
):
self.run_async = run_async
self._entry_points = entry_points
self._states = states
self._fallbacks = fallbacks
self._allow_reentry = allow_reentry
self._per_user = per_user
self._per_chat = per_chat
self._per_message = per_message
self._conversation_timeout = conversation_timeout
self._name = name
if persistent and not self.name:
raise ValueError("Conversations can't be persistent when handler is unnamed.")
2020-10-06 19:28:40 +02:00
self.persistent: bool = persistent
self._persistence: Optional[BasePersistence] = None
Documentation Improvements (#2008) * Minor doc updates, following official API docs * Fix spelling in Defaults docstrings * Clarify Changelog of v12.7 about aware dates * Fix typo in CHANGES.rst (#2024) * Fix PicklePersistence.flush() with only bot_data (#2017) * Update pylint in pre-commit to fix CI (#2018) * Add Filters.via_bot (#2009) * feat: via_bot filter also fixing a small mistake in the empty parameter of the user filter and improve docs slightly * fix: forgot to set via_bot to None * fix: redoing subclassing to copy paste solution * Cosmetic changes Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de> * Update CHANGES.rst Fixed Typo Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> * Update downloads badge, add info on IRC Channel to Getting Help section * Remove RegexHandler from ConversationHandlers Docs (#1973) Replaced RegexHandler with MessageHandler, since the former is deprecated * Fix Filters.via_bot docstrings * Add notes on Markdown v1 being legacy mode * Fixed typo in the Regex doc.. (#2036) * Typo: Spelling * Minor cleanup from #2043 * Document CommandHandler ignoring channel posts * Doc fixes for a few telegram.ext classes * Doc fixes for most `telegram` classes. * pep-8 forgot the hard wrap is at 99 chars, not 100! fixed a few spelling mistakes too. * Address review and made rendering of booleans consistent True, False, None are now rendered with ``bool`` wherever they weren't in telegram and telegram.ext classes. * Few doc fixes for inline* classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram/files classes As usual, docs were cross-checked with official tg api docs. * Doc fixes for telegram.Game Mostly just added hyperlinks. And fixed message length doc. As usual, docs were cross-checked with official tg api docs. * Very minor doc fix for passportfile.py and passportelementerrors.py Didn't bother changing too much since this seems to be a custom implementation. * Doc fixes for telegram.payments As usual, cross-checked with official bot api docs. * Address review 2 Few tiny other fixes too. * Changed from ``True/False/None`` to :obj:`True/False/None` project-wide. Few tiny other doc fixes too. Co-authored-by: Robert Geislinger <mitachundkrach@gmail.com> Co-authored-by: Poolitzer <25934244+Poolitzer@users.noreply.github.com> Co-authored-by: GauthamramRavichandran <30320759+GauthamramRavichandran@users.noreply.github.com> Co-authored-by: Mahesh19 <maheshvagicherla99438@gmail.com> Co-authored-by: hoppingturtles <ilovebhagwan@gmail.com>
2020-08-24 19:35:57 +02:00
""":obj:`telegram.ext.BasePersistence`: The persistence used to store conversations.
Set by dispatcher"""
self._map_to_parent = map_to_parent
self.timeout_jobs: Dict[Tuple[int, ...], 'Job'] = {}
self._timeout_jobs_lock = Lock()
self._conversations: ConversationDict = {}
self._conversations_lock = Lock()
self.logger = logging.getLogger(__name__)
if not any((self.per_user, self.per_chat, self.per_message)):
raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'")
if self.per_message and not self.per_chat:
2021-09-20 08:45:42 +02:00
warn(
"If 'per_message=True' is used, 'per_chat=True' should also be used, "
2021-09-20 08:45:42 +02:00
"since message IDs are not globally unique.",
stacklevel=2,
)
all_handlers: List[Handler] = []
all_handlers.extend(entry_points)
all_handlers.extend(fallbacks)
for state_handlers in states.values():
all_handlers.extend(state_handlers)
if self.per_message:
for handler in all_handlers:
if not isinstance(handler, CallbackQueryHandler):
2021-09-20 08:45:42 +02:00
warn(
"If 'per_message=True', all entry points, state handlers, and fallbacks"
" must be 'CallbackQueryHandler', since no other handlers "
2021-09-20 08:45:42 +02:00
"have a message context.",
stacklevel=2,
)
break
else:
for handler in all_handlers:
if isinstance(handler, CallbackQueryHandler):
2021-09-20 08:45:42 +02:00
warn(
"If 'per_message=False', 'CallbackQueryHandler' will not be "
2021-09-20 08:45:42 +02:00
"tracked for every message.",
stacklevel=2,
)
break
if self.per_chat:
for handler in all_handlers:
if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)):
2021-09-20 08:45:42 +02:00
warn(
"If 'per_chat=True', 'InlineQueryHandler' can not be used, "
2021-09-20 08:45:42 +02:00
"since inline queries have no chat context.",
stacklevel=2,
)
break
if self.conversation_timeout:
for handler in all_handlers:
if isinstance(handler, self.__class__):
2021-09-20 08:45:42 +02:00
warn(
"Using `conversation_timeout` with nested conversations is currently not "
"supported. You can still try to use it, but it will likely behave "
2021-09-20 08:45:42 +02:00
"differently from what you expect.",
stacklevel=2,
)
break
if self.run_async:
for handler in all_handlers:
handler.run_async = True
@property
2020-10-06 19:28:40 +02:00
def entry_points(self) -> List[Handler]:
"""List[:class:`telegram.ext.Handler`]: A list of ``Handler`` objects that can trigger the
start of the conversation.
"""
return self._entry_points
@entry_points.setter
def entry_points(self, value: object) -> NoReturn:
raise AttributeError(
"You can not assign a new value to entry_points after initialization."
)
@property
2020-10-06 19:28:40 +02:00
def states(self) -> Dict[object, List[Handler]]:
"""Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]: A :obj:`dict` that
defines the different states of conversation a user can be in and one or more
associated ``Handler`` objects that should be used in that state.
"""
return self._states
@states.setter
def states(self, value: object) -> NoReturn:
raise AttributeError("You can not assign a new value to states after initialization.")
@property
2020-10-06 19:28:40 +02:00
def fallbacks(self) -> List[Handler]:
"""List[:class:`telegram.ext.Handler`]: A list of handlers that might be used if
the user is in a conversation, but every handler for their current state returned
:obj:`False` on :attr:`check_update`.
"""
return self._fallbacks
@fallbacks.setter
def fallbacks(self, value: object) -> NoReturn:
raise AttributeError("You can not assign a new value to fallbacks after initialization.")
@property
2020-10-06 19:28:40 +02:00
def allow_reentry(self) -> bool:
""":obj:`bool`: Determines if a user can restart a conversation with an entry point."""
return self._allow_reentry
@allow_reentry.setter
def allow_reentry(self, value: object) -> NoReturn:
raise AttributeError(
"You can not assign a new value to allow_reentry after initialization."
)
@property
2020-10-06 19:28:40 +02:00
def per_user(self) -> bool:
""":obj:`bool`: If the conversation key should contain the User's ID."""
return self._per_user
@per_user.setter
def per_user(self, value: object) -> NoReturn:
raise AttributeError("You can not assign a new value to per_user after initialization.")
@property
2020-10-06 19:28:40 +02:00
def per_chat(self) -> bool:
""":obj:`bool`: If the conversation key should contain the Chat's ID."""
return self._per_chat
@per_chat.setter
def per_chat(self, value: object) -> NoReturn:
raise AttributeError("You can not assign a new value to per_chat after initialization.")
@property
2020-10-06 19:28:40 +02:00
def per_message(self) -> bool:
""":obj:`bool`: If the conversation key should contain the message's ID."""
return self._per_message
@per_message.setter
def per_message(self, value: object) -> NoReturn:
raise AttributeError("You can not assign a new value to per_message after initialization.")
@property
def conversation_timeout(
self,
) -> Optional[Union[float, datetime.timedelta]]:
""":obj:`float` | :obj:`datetime.timedelta`: Optional. When this
handler is inactive more than this timeout (in seconds), it will be automatically
ended.
"""
return self._conversation_timeout
@conversation_timeout.setter
def conversation_timeout(self, value: object) -> NoReturn:
raise AttributeError(
"You can not assign a new value to conversation_timeout after initialization."
)
@property
2020-10-06 19:28:40 +02:00
def name(self) -> Optional[str]:
""":obj:`str`: Optional. The name for this :class:`ConversationHandler`."""
return self._name
@name.setter
def name(self, value: object) -> NoReturn:
raise AttributeError("You can not assign a new value to name after initialization.")
@property
2020-10-06 19:28:40 +02:00
def map_to_parent(self) -> Optional[Dict[object, object]]:
"""Dict[:obj:`object`, :obj:`object`]: Optional. A :obj:`dict` that can be
used to instruct a nested :class:`ConversationHandler` to transition into a mapped state on
its parent :class:`ConversationHandler` in place of a specified nested state.
"""
return self._map_to_parent
@map_to_parent.setter
def map_to_parent(self, value: object) -> NoReturn:
raise AttributeError(
"You can not assign a new value to map_to_parent after initialization."
)
@property
2020-10-06 19:28:40 +02:00
def persistence(self) -> Optional[BasePersistence]:
"""The persistence class as provided by the :class:`Dispatcher`."""
return self._persistence
@persistence.setter
2020-10-06 19:28:40 +02:00
def persistence(self, persistence: BasePersistence) -> None:
self._persistence = persistence
# Set persistence for nested conversations
for handlers in self.states.values():
for handler in handlers:
if isinstance(handler, ConversationHandler):
handler.persistence = self.persistence
@property
def conversations(self) -> ConversationDict: # skipcq: PY-D0003
return self._conversations
@conversations.setter
2020-10-06 19:28:40 +02:00
def conversations(self, value: ConversationDict) -> None:
self._conversations = value
# Set conversations for nested conversations
for handlers in self.states.values():
for handler in handlers:
2020-10-06 19:28:40 +02:00
if isinstance(handler, ConversationHandler) and self.persistence and handler.name:
handler.conversations = self.persistence.get_conversations(handler.name)
2020-10-06 19:28:40 +02:00
def _get_key(self, update: Update) -> Tuple[int, ...]:
chat = update.effective_chat
user = update.effective_user
key = []
if self.per_chat:
2020-10-06 19:28:40 +02:00
key.append(chat.id) # type: ignore[union-attr]
if self.per_user and user is not None:
key.append(user.id)
if self.per_message:
key.append(
update.callback_query.inline_message_id # type: ignore[union-attr]
or update.callback_query.message.message_id # type: ignore[union-attr]
)
return tuple(key)
def _resolve_promise(self, state: Tuple) -> object:
old_state, new_state = state
try:
res = new_state.result(0)
res = res if res is not None else old_state
except Exception as exc:
self.logger.exception("Promise function raised exception")
self.logger.exception("%s", exc)
res = old_state
finally:
if res is None and old_state is None:
res = self.END
return res
def _schedule_job(
self,
new_state: object,
dispatcher: 'Dispatcher[Any, CCT, Any, Any, Any, JobQueue, Any]',
update: Update,
2021-08-29 18:15:04 +02:00
context: CallbackContext,
conversation_key: Tuple[int, ...],
) -> None:
if new_state != self.END:
try:
# both job_queue & conversation_timeout are checked before calling _schedule_job
j_queue = dispatcher.job_queue
self.timeout_jobs[conversation_key] = j_queue.run_once(
self._trigger_timeout,
self.conversation_timeout, # type: ignore[arg-type]
context=_ConversationTimeoutContext(
conversation_key, update, dispatcher, context
),
)
except Exception as exc:
self.logger.exception(
"Failed to schedule timeout job due to the following exception:"
)
self.logger.exception("%s", exc)
# pylint: disable=too-many-return-statements
def check_update(self, update: object) -> CheckUpdateType:
"""
Determines whether an update should be handled by this conversationhandler, and if so in
which state the conversation currently is.
Args:
update (:class:`telegram.Update` | :obj:`object`): Incoming update.
Returns:
:obj:`bool`
2017-09-01 08:43:08 +02:00
"""
if not isinstance(update, Update):
return None
# Ignore messages in channels
if update.channel_post or update.edited_channel_post:
return None
if self.per_chat and not update.effective_chat:
return None
if self.per_message and not update.callback_query:
return None
if update.callback_query and self.per_chat and not update.callback_query.message:
return None
key = self._get_key(update)
with self._conversations_lock:
state = self.conversations.get(key)
# Resolve promises
if isinstance(state, tuple) and len(state) == 2 and isinstance(state[1], Promise):
self.logger.debug('waiting for promise...')
# check if promise is finished or not
if state[1].done.wait(0):
res = self._resolve_promise(state)
self._update_state(res, key)
with self._conversations_lock:
state = self.conversations.get(key)
# if not then handle WAITING state instead
else:
2020-10-06 19:28:40 +02:00
hdlrs = self.states.get(self.WAITING, [])
for hdlr in hdlrs:
check = hdlr.check_update(update)
if check is not None and check is not False:
2020-10-06 19:28:40 +02:00
return key, hdlr, check
return None
self.logger.debug('selecting conversation %s with state %s', str(key), str(state))
handler = None
# Search entry points for a match
if state is None or self.allow_reentry:
for entry_point in self.entry_points:
check = entry_point.check_update(update)
if check is not None and check is not False:
handler = entry_point
break
else:
if state is None:
return None
# Get the handler list for current state, if we didn't find one yet and we're still here
if state is not None and not handler:
handlers = self.states.get(state)
for candidate in handlers or []:
check = candidate.check_update(update)
if check is not None and check is not False:
handler = candidate
break
# Find a fallback handler if all other handlers fail
else:
for fallback in self.fallbacks:
check = fallback.check_update(update)
if check is not None and check is not False:
handler = fallback
break
else:
return None
2020-10-06 19:28:40 +02:00
return key, handler, check # type: ignore[return-value]
def handle_update( # type: ignore[override]
self,
update: Update,
dispatcher: 'Dispatcher',
check_result: CheckUpdateType,
2021-08-29 18:15:04 +02:00
context: CallbackContext,
) -> Optional[object]:
2017-09-01 08:43:08 +02:00
"""Send the update to the callback for the current state and Handler
Args:
check_result: The result from check_update. For this handler it's a tuple of key,
handler, and the handler's check result.
update (:class:`telegram.Update`): Incoming telegram update.
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
2021-08-29 18:15:04 +02:00
context (:class:`telegram.ext.CallbackContext`): The context as provided by
2020-10-06 19:28:40 +02:00
the dispatcher.
2017-09-01 08:43:08 +02:00
"""
2020-10-06 19:28:40 +02:00
conversation_key, handler, check_result = check_result # type: ignore[assignment,misc]
raise_dp_handler_stop = False
with self._timeout_jobs_lock:
# Remove the old timeout job (if present)
timeout_job = self.timeout_jobs.pop(conversation_key, None)
if timeout_job is not None:
timeout_job.schedule_removal()
try:
new_state = handler.handle_update(update, dispatcher, check_result, context)
except DispatcherHandlerStop as exception:
new_state = exception.state
raise_dp_handler_stop = True
with self._timeout_jobs_lock:
if self.conversation_timeout:
if dispatcher.job_queue is not None:
# Add the new timeout job
if isinstance(new_state, Promise):
new_state.add_done_callback(
functools.partial(
self._schedule_job,
dispatcher=dispatcher,
update=update,
context=context,
conversation_key=conversation_key,
)
)
elif new_state != self.END:
self._schedule_job(
new_state, dispatcher, update, context, conversation_key
)
else:
2021-09-20 08:45:42 +02:00
warn(
"Ignoring `conversation_timeout` because the Dispatcher has no JobQueue.",
)
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
self._update_state(self.END, conversation_key)
if raise_dp_handler_stop:
raise DispatcherHandlerStop(self.map_to_parent.get(new_state))
return self.map_to_parent.get(new_state)
self._update_state(new_state, conversation_key)
if raise_dp_handler_stop:
# Don't pass the new state here. If we're in a nested conversation, the parent is
# expecting None as return value.
raise DispatcherHandlerStop()
2020-10-06 19:28:40 +02:00
return None
def _update_state(self, new_state: object, key: Tuple[int, ...]) -> None:
if new_state == self.END:
with self._conversations_lock:
if key in self.conversations:
# If there is no key in conversations, nothing is done.
del self.conversations[key]
2020-10-06 19:28:40 +02:00
if self.persistent and self.persistence and self.name:
self.persistence.update_conversation(self.name, key, None)
elif isinstance(new_state, Promise):
with self._conversations_lock:
self.conversations[key] = (self.conversations.get(key), new_state)
2020-10-06 19:28:40 +02:00
if self.persistent and self.persistence and self.name:
self.persistence.update_conversation(
self.name, key, (self.conversations.get(key), new_state)
)
elif new_state is not None:
if new_state not in self.states:
2021-09-20 08:45:42 +02:00
warn(
f"Handler returned state {new_state} which is unknown to the "
2021-09-20 08:45:42 +02:00
f"ConversationHandler{' ' + self.name if self.name is not None else ''}.",
)
with self._conversations_lock:
self.conversations[key] = new_state
2020-10-06 19:28:40 +02:00
if self.persistent and self.persistence and self.name:
self.persistence.update_conversation(self.name, key, new_state)
2021-08-29 18:15:04 +02:00
def _trigger_timeout(self, context: CallbackContext) -> None:
self.logger.debug('conversation timeout was triggered!')
2019-04-05 20:03:44 +02:00
2021-08-29 18:15:04 +02:00
job = cast('Job', context.job)
ctxt = cast(_ConversationTimeoutContext, job.context)
callback_context = ctxt.callback_context
with self._timeout_jobs_lock:
found_job = self.timeout_jobs[ctxt.conversation_key]
if found_job is not job:
# The timeout has been cancelled in handle_update
return
del self.timeout_jobs[ctxt.conversation_key]
2019-04-05 20:03:44 +02:00
handlers = self.states.get(self.TIMEOUT, [])
for handler in handlers:
check = handler.check_update(ctxt.update)
if check is not None and check is not False:
try:
handler.handle_update(ctxt.update, ctxt.dispatcher, check, callback_context)
except DispatcherHandlerStop:
2021-09-20 08:45:42 +02:00
warn(
'DispatcherHandlerStop in TIMEOUT state of '
2021-09-20 08:45:42 +02:00
'ConversationHandler has no effect. Ignoring.',
)
self._update_state(self.END, ctxt.conversation_key)