I have a function that I need to be able to both execute by sending a command and execute automatically using a job queue. And in that function I need to have access to user_data
to store data that is specific to each user. Now the problem is that when I try to execute it via job queue, user_data
is None
and thus unavailable. How can I fix that?
Here's how I'm currently doing this, simplified:
import datetime
from settings import TEST_TOKEN, BACKUP_USER
from telegram.ext import Updater, CommandHandler, CallbackContext
from pytz import timezone
def job_daily(context: CallbackContext):
job(BACKUP_USER, context)
def job_command(update, context):
job(update.message.chat_id, context)
def job(chat_id, context):
print(context.user_data)
def main():
updater = Updater(TEST_TOKEN, use_context=True)
dispatcher = updater.dispatcher
job_queue = updater.job_queue
# To run it automatically
tehran = timezone("Asia/Tehran")
due = datetime.time(15, 3, tzinfo=tehran)
job_queue.run_daily(job_daily, due)
# To run it via command
dispatcher.add_handler(CommandHandler("job", job_command))
updater.start_polling()
updater.idle()
if __name__ == "__main__":
main()
Now when I send the command /job
and thus executing job_command
, the job
function prints {}
which means that I can access user_data
. But when the job_daily
function is executed, the job
function prints None
meaning that I don't have access to user_data
. Same goes for chat_data
.
In a callback function of python-telegram-bot
, context.user_data
and context.chat_data
depend on the update
. More precisely, PTB takes update.effective_user/chat.id
and provides the corresponding user/chat_data
. Jobs callbacks are not triggered by an update
(but by a time based trigger), so there's no reasonable way to provide context.user_data
.
What you can do, when scheduling the job from within a handler callback, where user_data
is available, is to pass it as context
argument to the job:
context.job_queue.run_*(..., context=context.user_data)
Then within the job callback, you can retrieve it as user_data = context.job.context
In your case, you schedule the job in main
, which is not a handler callback and hence you don't have context.user_data
(not even context
). If you have a specific user id for which you'd like to pass the user_data
, you can get that user_data
as user_data = updater.dispatcher.user_data[user_id]
, which is the same object as context.user_data
(for updates from this particular user).
Disclaimer: I'm currently the maintainer of python-telegram-bot
.