I am trying to add to a Telegram bot a timer which runs and sends a message every x time.
Getting always the error: x argument have not been supplied from the callback function, even though I am putting those arguments in the context argument when calling run_repeating.
The call to run_repeating:
context.job_queue.run_repeating(stupid_hello,
interval=30,
context={'bot': context.bot,'chat_id':update.message.chat_id},
first=datetime.time(hour=8),
last=datetime.time(hour=22))
callback function:
def stupid_hello(bot, chat_id):
bot.send_message(chat_id=chat_id ,text='Hello World')
And this is how I set the handler:
dp.add_handler(CommandHandler("start", start, pass_job_queue=True))
The run_repeating function is part of a "start" function.
--- EDIT ---
Adding code to reproduce it:
import logging
from re import sub
from typing import Set
import praw
from collections import Counter
from praw.models import MoreComments
import os
import datetime
from telegram import Update
from telegram.ext import Updater, CommandHandler, CallbackContext
import config
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
def stupid_hello(bot, chat_id):
bot.send_message(chat_id=chat_id ,text='Hello World')
def start(update: Update, context: CallbackContext):
context.job_queue.run_repeating(stupid_hello, interval=30,
context={'bot': context.bot, 'chat_id':update.message.chat_id},
first=datetime.time(hour=8),
last=datetime.time(hour=22))
def help(update, context):
"""Send a message when the command /help is issued."""
update.message.reply_text('/start, /top_ten_satoshi')
def error(update, context):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, context.error)
def main():
"""Start the bot."""
# Create the Updater and pass it your bot's token.
# Make sure to set use_context=True to use the new context based callbacks
# Post version 12 this will no longer be necessary
updater = Updater(config.telegram_token, use_context=True)
# Get the dispatcher to register handlers
dp = updater.dispatcher
# on different commands - answer in Telegram
dp.add_handler(CommandHandler("start", start, pass_job_queue=True))
dp.add_handler(CommandHandler("help", help))
# log all errors
dp.add_error_handler(error)
# Start bot for local usage
updater.start_polling()
# Run the bot until you press Ctrl-C or the process receives SIGINT,
# SIGTERM or SIGABRT. This should be used most of the time, since
# start_polling() is non-blocking and will stop the bot gracefully.
updater.idle()
if __name__ == '__main__':
main()
If you want to reproduce it you will need to add a config.py with your own telegram bot token and send /start to the bot from telegram
I found the solution in Python Telegram Bot, unable to pass job queue?
I thought the problem was related with the run_repeating function when it was with the job_queue.
Hope this helps others having the same issue.
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, InlineQueryHandler
def sayhi(context):
context.bot.send_message(context.job.context, text="hi")
def time(update, context):
context.job_queue.run_repeating(sayhi, 5, context=update.message.chat_id)
def main():
updater = Updater('Token', use_context=True)
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.text , time))
updater.start_polling()
updater.idle()
main()
As you can see the context keyword argument in run_repeating is referenced in the callback function as context.job.context which is the part I was missing
Related
I want to send a Message(call a function) every day at a given Time. Sadly this is not possible with message.reply_text('Test'). Is there any way i can do this? I could not find anything.
This is my current code:
import telegram.ext
from telegram.ext import CommandHandler, MessageHandler, Filters
import schedule
import time
API_KEY = 'XXXXXXXXXXX'
updater = telegram.ext.Updater(API_KEY)
dispatcher = updater.dispatcher
def start(update, context):
update.message.reply_text('Welcome!')
# problem:
def Test(update, context):
update.message.reply_text('Works!!!')
# running special functions every Day at a given Time
schedule.every().day.at("10:00").do(Test)
while True:
schedule.run_pending()
time.sleep(1)
def main():
# add handlers for start and help commands
dispatcher.add_handler(CommandHandler("start", start))
# start your bot
updater.start_polling()
# run the bot until Ctrl-C
updater.idle()
The schedule part works, I just don`t know how to send this Message.
Thanks for your help!
Update object, inside of the message field, has the from field which is a User Telegram object containing the user's ID.
Once you have the user's ID, you can use the sendMessage method in order to reply him easily.
To conclude, instead of:
update.message.reply_text('Welcome!')
You could do like so:
user_id = update.message.from.id
updater.sendmessage(chat_id=user_id, text="Welcome!")
Is there a way to send a message (call a function), without a command from the bot's user? For example when a certain condition is met?
Currently I have only been able to call a function with a command.
I have been trying the following:
from telegram.ext import Updater, CommandHandler, CallbackContext
from telegram import Update
from datetime import datetime
import telebot as tb
import logging
bot = tb.TeleBot(API_KEY)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
)
logger = logging.getLogger(__name__)
def messager(update: Update, context: CallbackContext) -> None:
"""this function messages at a specific time"""
update.message.reply_text("message back")
if __name__ == "__main__":
updater = Updater(API_KEY)
dispatcher = updater.dispatcher
dispatcher.add_handler(CommandHandler("message", messager))
condition = False #I have been changing this when testing
if (condition == True):
messager() # how to call messager here? how to pass update and context arguments?
updater.start_polling()
updater.idle()
Any possible way to achieve this would be great.
You cannot call a function using update and context since there is no update from the telegram servers to act on. In other words there is no event to perform a callback on.
Depending on what you want to do you could use a MessageHandler instead of a CommandHandler to reply to any message with Filters to filter out which ones to reply to
or if you want to send a message every time you start your bot and you know who to send a message to (i.e you have their chat_id) you can do
if condition:
updater.bot.send_message(chat_id=CHAT_ID, text="message back")
or if you just want to send a message every time some user starts a chat with your bot you could use the start command which is sent by default to start a chat with a bot
I'm currently making a Telegram using Python. I was wondering how to make a functional buttons like this
https://i.stack.imgur.com/e3eMb.png
I would like to make /command command to have button that says "This is a button". How do I make it? Here's my code to help :
# Modules needed
import time
from time import sleep
import random
import logging
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
# /command
def command(update, context):
update.message.reply_text("Reply here")
def error(update, context):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, context.error)
def main():
"""Start the bot."""
# Create the Updater and pass it your bot's token.
updater = Updater("[TOKEN]", use_context=True)
# Get the dispatcher to register handlers
dp = updater.dispatcher
# on different commands - answer in Telegram
dp.add_handler(CommandHandler("command", command))
# log all errors
dp.add_error_handler(error)
# Start the Bot
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
What you are looking for are so called inline buttons. Check out the official docs and this python-telegram-bot example.
Disclaimer: I'm currently the maintainer of python-telegram-bot.
I copied this code from another thread as is, but was unable to get it to work...
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, InlineQueryHandler
def sayhi(bot, job):
job.context.message.reply_text("hi")
def time(bot, update,job_queue):
job = job_queue.run_repeating(sayhi, 5, context=update)
def main():
updater = Updater('BotKey')
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.text , time,pass_job_queue=True))
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
The Error I was give in my command terminal is:
TypeError: time() missing 1 required positional argument: 'job_queue'
I found this strange as I thought I already had set pass_job_queue=True...
(also, I did change the BotKey to the required key. I can get my bot to reply to texts but cant get it to periodically send stuff...)
pass_job_queue was deprecated in version 12.0.0, Tutorial to switch version here
You need to use context based callbacks, like in this example.
Here's your code changed:
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, InlineQueryHandler
def sayhi(context):
context.bot.send_message(context.job.context, text="hi")
def time(update, context):
context.job_queue.run_repeating(sayhi, 5, context=update.message.chat_id)
def main():
updater = Updater('Token', use_context=True)
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.text , time))
updater.start_polling()
updater.idle()
main()
I'm trying to make a telegram bot with https://github.com/python-telegram-bot/python-telegram-bot library in python3.
I want to make a message sender bot. This is my code now:
#!/usr/bin/env python
"""#==============================# Imports #==============================#"""
import logging, time, telegram
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
from datetime import datetime
"""#==============================# Enable logging #==============================#"""
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.WARN)#DEBUG)
logger = logging.getLogger(__name__)
"""#==============================# Log error #==============================#"""
def error(update, context):
#Log Errors caused by Updates.
logger.warning("Update '%s' caused error '%s'", update, context.error)
"""#==============================# Bot commands #==============================#"""
def start(update, context):
update.message.reply_text("Bot joined the conversation!")
def get_additional_updates(update, message):
***My Problem***
"""#==============================# MAIN #==============================#"""
def main():
updater = Updater("<TOKEN>", use_context=True)
# Get the dispatcher to register handlers
dp = updater.dispatcher
# on different commands - answer in Telegram
dp.add_handler(CommandHandler("start", start)
dp.add_handler(CommandHandler("send", get_additional_updates)
# log all errors
dp.add_error_handler(error)
# Start the Bot
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
I don't know what should I do to get the updates inside the 'get_additional_updates' function.
What I want to do, is: I type /send, after this the bot waits for my message, I type my message in and send it. The problem is, that I can't figure it out how to get the second message (the message itself) to the 'get_additional_updates' function.
I can't find it in the documentation, and I'm very new to programming as well.
Please help me with the code I need to type there in order to get the additional messages.
Let me know if you can't understand what is my question, I'll try to explain better.
Thanks a lot!
P.S.:Sorry, if my english is bad, I'm trying to upgrade that as well.
You should use conversation bot ,Check the example here