Make chat/user_data Available in Error Handler for Errors in Jobs (#3152)

This commit is contained in:
Bibo-Joshi 2022-07-11 07:54:03 +02:00 committed by GitHub
parent 1e703a0be5
commit 460aaf8bb6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 7 deletions

View file

@ -160,6 +160,9 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
``chat_data`` needs to be transferred. For details see our `wiki page
<https://github.com/python-telegram-bot/python-telegram-bot/wiki/
Storing-bot,-user-and-chat-related-data#chat-migration>`_.
.. versionchanged:: 20.0
The chat data is now also present in error handlers if the error is caused by a job.
"""
if self._chat_id is not None:
return self._application.chat_data[self._chat_id]
@ -176,6 +179,9 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
""":obj:`ContextTypes.user_data`: Optional. An object that can be used to keep any data in.
For each update from the same user it will be the same :obj:`ContextTypes.user_data`.
Defaults to :obj:`dict`.
.. versionchanged:: 20.0
The user data is now also present in error handlers if the error is caused by a job.
"""
if self._user_id is not None:
return self._application.user_data[self._user_id]
@ -275,10 +281,16 @@ class CallbackContext(Generic[BT, UD, CD, BD]):
Returns:
:class:`telegram.ext.CallbackContext`
"""
self = cls.from_update(update, application)
# update and job will never be present at the same time
if update is not None:
self = cls.from_update(update, application)
elif job is not None:
self = cls.from_job(job, application)
else:
self = cls(application) # type: ignore
self.error = error
self.coroutine = coroutine
self.job = job
return self
@classmethod

View file

@ -30,7 +30,7 @@ from telegram import (
User,
)
from telegram.error import TelegramError
from telegram.ext import ApplicationBuilder, CallbackContext
from telegram.ext import ApplicationBuilder, CallbackContext, Job
"""
CallbackContext.refresh_data is tested in TestBasePersistence
@ -116,11 +116,10 @@ class TestCallbackContext:
update = Update(
0, message=Message(0, None, Chat(1, "chat"), from_user=User(1, "user", False))
)
job = object()
coroutine = object()
callback_context = CallbackContext.from_error(
update=update, error=error, application=app, job=job, coroutine=coroutine
update=update, error=error, application=app, coroutine=coroutine
)
assert callback_context.error is error
@ -131,6 +130,22 @@ class TestCallbackContext:
assert callback_context.job_queue is app.job_queue
assert callback_context.update_queue is app.update_queue
assert callback_context.coroutine is coroutine
def test_from_error_job_user_chat_data(self, app):
error = TelegramError("test")
job = Job(callback=lambda x: x, data=None, chat_id=42, user_id=43)
callback_context = CallbackContext.from_error(
update=None, error=error, application=app, job=job
)
assert callback_context.error is error
assert callback_context.chat_data == {}
assert callback_context.user_data == {}
assert callback_context.bot_data is app.bot_data
assert callback_context.bot is app.bot
assert callback_context.job_queue is app.job_queue
assert callback_context.update_queue is app.update_queue
assert callback_context.job is job
def test_match(self, app):

View file

@ -86,7 +86,12 @@ class TestJobQueue:
self.job_time = time.time()
async def error_handler_context(self, update, context):
self.received_error = (str(context.error), context.job)
self.received_error = (
str(context.error),
context.job,
context.user_data,
context.chat_data,
)
async def error_handler_raise_error(self, *args):
raise Exception("Failing bigly")
@ -453,7 +458,7 @@ class TestJobQueue:
async def test_process_error_context(self, job_queue, app):
app.add_error_handler(self.error_handler_context)
job = job_queue.run_once(self.job_with_exception, 0.1)
job = job_queue.run_once(self.job_with_exception, 0.1, chat_id=42, user_id=43)
await asyncio.sleep(0.15)
assert self.received_error[0] == "Test Error"
assert self.received_error[1] is job
@ -461,6 +466,8 @@ class TestJobQueue:
await job.run(app)
assert self.received_error[0] == "Test Error"
assert self.received_error[1] is job
assert self.received_error[2] is app.user_data[43]
assert self.received_error[3] is app.chat_data[42]
# Remove handler
app.remove_error_handler(self.error_handler_context)