Pass last valid context to TIMEOUT handlers (#1826)

This commit is contained in:
Bibo-Joshi 2020-04-10 13:18:43 +02:00 committed by GitHub
parent 3101ea8432
commit bdf0cb91f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 7 deletions

View file

@ -29,10 +29,11 @@ from telegram.utils.promise import Promise
class _ConversationTimeoutContext(object):
def __init__(self, conversation_key, update, dispatcher):
def __init__(self, conversation_key, update, dispatcher, callback_context):
self.conversation_key = conversation_key
self.update = update
self.dispatcher = dispatcher
self.callback_context = callback_context
class ConversationHandler(Handler):
@ -96,8 +97,9 @@ class ConversationHandler(Handler):
conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`): Optional. When this
handler is inactive more than this timeout (in seconds), it will be automatically
ended. If this value is 0 (default), there will be no timeout. When it's triggered, the
last received update will be handled by ALL the handler's who's `check_update` method
returns True that are in the state :attr:`ConversationHandler.TIMEOUT`.
last received update and the corresponding ``context`` will be handled by ALL the
handler's who's `check_update` method returns True that are in the state
:attr:`ConversationHandler.TIMEOUT`.
name (:obj:`str`): Optional. The name for this conversationhandler. Required for
persistence
persistent (:obj:`bool`): Optional. If the conversations dict for this handler should be
@ -130,8 +132,9 @@ class ConversationHandler(Handler):
conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`, optional): When this
handler is inactive more than this timeout (in seconds), it will be automatically
ended. If this value is 0 or None (default), there will be no timeout. The last
received update will be handled by ALL the handler's who's `check_update` method
returns True that are in the state :attr:`ConversationHandler.TIMEOUT`.
received update and the corresponding ``context`` will be handled by ALL the handler's
who's `check_update` method returns True that are in the state
:attr:`ConversationHandler.TIMEOUT`.
name (:obj:`str`, optional): The name for this conversationhandler. Required for
persistence
persistent (:obj:`bool`, optional): If the conversations dict for this handler should be
@ -466,7 +469,8 @@ class ConversationHandler(Handler):
# Add the new timeout job
self.timeout_jobs[conversation_key] = dispatcher.job_queue.run_once(
self._trigger_timeout, self.conversation_timeout,
context=_ConversationTimeoutContext(conversation_key, update, dispatcher))
context=_ConversationTimeoutContext(conversation_key, update,
dispatcher, context))
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
self.update_state(self.END, conversation_key)
@ -503,9 +507,9 @@ class ConversationHandler(Handler):
callback_context = None
if isinstance(context, CallbackContext):
job = context.job
callback_context = context
context = job.context
callback_context = context.callback_context
with self._timeout_jobs_lock:
found_job = self.timeout_jobs[context.conversation_key]

View file

@ -546,6 +546,43 @@ class TestConversationHandler(object):
dp.job_queue.tick()
assert handler.conversations.get((self.group.id, user1.id)) is None
def test_conversation_handler_timeout_update_and_context(self, cdp, bot, user1):
context = None
def start_callback(u, c):
nonlocal context, self
context = c
return self.start(u, c)
states = self.states
timeout_handler = CommandHandler('start', None)
states.update({ConversationHandler.TIMEOUT: [timeout_handler]})
handler = ConversationHandler(entry_points=[CommandHandler('start', start_callback)],
states=states, fallbacks=self.fallbacks,
conversation_timeout=0.5)
cdp.add_handler(handler)
# Start state machine, then reach timeout
message = Message(0, user1, None, self.group, text='/start',
entities=[MessageEntity(type=MessageEntity.BOT_COMMAND, offset=0,
length=len('/start'))],
bot=bot)
update = Update(update_id=0, message=message)
def timeout_callback(u, c):
nonlocal update, context, self
self.is_timeout = True
assert u is update
assert c is context
timeout_handler.callback = timeout_callback
cdp.process_update(update)
sleep(0.5)
cdp.job_queue.tick()
assert handler.conversations.get((self.group.id, user1.id)) is None
assert self.is_timeout
def test_conversation_timeout_keeps_extending(self, dp, bot, user1):
handler = ConversationHandler(entry_points=self.entry_points, states=self.states,
fallbacks=self.fallbacks, conversation_timeout=0.5)