Передать аргументы при вызове функции в python-telegram-bot
Есть строка job_queue.run_repeating(ericsson_alarm, interval=10, first=10, data=controllers)
, которая вызывает функцию ericsson_alarm, в нее нужно передать аргумент controllers. Как это сделать? Пробовал и лямбдами и всем остальным, не получается, буду рад любой подсказке
import logging
import ericsson
import configparser
from telegram import Update
from telegram.ext import ContextTypes, CommandHandler, Application
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
def _ericsson():
config = configparser.ConfigParser()
config.read('config.ini')
controllers = {}
for section in config.sections():
if 'MSC' in section:
# Распаковываем словарь в аргументы функции
controllers[section] = ericsson.EricssonTelnet(**dict(config.items(section)))
controllers[section].get_alarms()
return controllers
async def ericsson_alarm(update: Update, context: ContextTypes.DEFAULT_TYPE):
controllers = context.job.context['controllers']
for controller in controllers.values():
alarm = controller.get_alarms()
if alarm:
await context.bot.send_message(chat_id='-ID', text=f"<code>{alarm}</code>")
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
def main() -> None:
application = Application.builder().token('TOKEN').build()
controllers = _ericsson()
# Для отправки сообщений по таймеру
job_queue = application.job_queue
# Команды
start_handler = CommandHandler('start', start)
# Вызываем функции по-таймеру
job_queue.run_repeating(ericsson_alarm, interval=10, first=10, data=controllers)
application.add_handler(start_handler)
application.run_polling()
if __name__ == '__main__':
main()
Ответы (4 шт):
Варианты:
Использовать функцию без параметров (параметры сохранить в переменные и использовать эти переменные)
Пример:
updater = Updater(token='YOUR_TOKEN', use_context=True) dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler('start', <func_name>, <param1> = <value>, <param2> = <value>))
Параметр data
это переименованный в версии 20.0 context
. То есть из data
будет браться только объект 'context'. Это прописано и в описании к самому классу JobQueue.
Если вы выведите в print
context.job
, то увидите объект класса Job
в виде:
Job[id=ид, name=ericsson_alarm, callback=ericsson_alarm, trigger=тригер]
Просто, что бы понимали как это работает и что из чего вы пытаетесь достать. Из context.user_data
так же ничего не получится извлечь, тк объект будет пустым None
.
Поэтому самый простой и очевидный способ это создать словарь глобально и все необходимые данные брать из этого словаря:
def _ericsson():
config = configparser.ConfigParser()
config.read('config.ini')
controllers = {}
for section in config.sections():
if 'MSC' in section:
# Распаковываем словарь в аргументы функции
controllers[section] = ericsson.EricssonTelnet(**dict(config.items(section)))
controllers[section].get_alarms()
return controllers
controllers = _ericsson() # будет доступна во всех функциях прописанных ниже
Важно отметить, что run_repeating
начинает работу сразу после запуска бота, и отправлять сообщения из вызываемой функции можно только используя конкретный id
чата. При этом пользователь по этому id
должен предварительно начать диалог с ботом, иначе бот не сможет ничего ему отправить - защита ТГ от спама. Если же это групповой чат, то соответственно права в группе на отправку сообщений.
Исправленный код:
def _ericsson():
config = configparser.ConfigParser()
config.read('config.ini')
controllers = {}
for section in config.sections():
if 'MSC' in section:
# Распаковываем словарь в аргументы функции
controllers[section] = ericsson.EricssonTelnet(**dict(config.items(section)))
controllers[section].get_alarms()
return controllers
controllers = _ericsson()
async def ericsson_alarm(context: ContextTypes.DEFAULT_TYPE):
for controller in controllers.values():
alarm = controller.get_alarms()
if alarm:
await context.bot.send_message(chat_id='-ID', text=f"<code>{alarm}</code>")
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
def main() -> None:
application = Application.builder().token('TOKEN').build()
# Команды
start_handler = CommandHandler('start', start)
# Для отправки сообщений по таймеру
job_queue = application.job_queue
# Вызываем функции по-таймеру
job_queue.run_repeating(ericsson_alarm, interval=10, first=10, data=job_queue) # либо data можно вообще не указывать, по умолчанию будет передаваться context
application.add_handler(start_handler)
application.run_polling()
Думаю, можно сделать как-то так:
async def ericsson_alarm(update: Update, context: ContextTypes.DEFAULT_TYPE):
async def ericsson_alarm(controllers, update: Update, context: ContextTypes.DEFAULT_TYPE):
job_queue.run_repeating(ericsson_alarm, interval=10, first=10, data=controllers)
job_queue.run_repeating(lambda update, context: ericsson_alarm(controllers, update, context), interval=10, first=10)
Или (судя по документации версии 21.3) и с учётом того, что параметр update
в ericsson_alarm
вообще не использовался, как-то так:
async def ericsson_alarm(update: Update, context: ContextTypes.DEFAULT_TYPE):
async def ericsson_alarm(controllers, context: ContextTypes.DEFAULT_TYPE):
job_queue.run_repeating(ericsson_alarm, interval=10, first=10, data=controllers)
job_queue.run_repeating(lambda context: ericsson_alarm(controllers, context), interval=10, first=10)
попробуйте так
context.job_queue.run_repeating(ericsson_alarm, interval=10, first=10, data=[controllers])
распаковка
def ericsson_alarm(context):
data=context.job.data
callback - функция обратного вызова.
job_kwargs=None - словарь: произвольные ключевого аргументы для передачи в scheduler.add_job().
data=None - дополнительные данные, необходимые для функции обратного вызова. Доступ к Job.data можно получить в функции обратного вызова через context.job.data. По умолчанию значение равно None. (Изменено в версии 20.0: аргумент context переименован в data.)
name=None - имя задания. По умолчанию callback.__name__.
chat_id - идентификатор чата, связанного с этим заданием. Если передано, то соответствующие данные chat_data будут доступны в обратном вызове. (Новое в версии 20.0.)
user_id - идентификатор пользователя, связанного с этим заданием. Если передано, соответствующие user_data будут доступны в обратном вызове. (Новое в версии 20.0.)
job_kwargs=None - произвольные ключевые аргументы для передачи в apscheduler.schedulers.base.BaseScheduler.add_job().