How to stop a loop in the command in the Telegram robot - python

I am building a telegram robot with python-telegram-bot
I want to do something in the loop and the user clicks on the menu to stop that command in the loop.
But the back button and menu do not work, so the back button does not work until the loop is finished.
my code
def callback_menu(update, context):
if update.message.text == "menu":
update = update.message
key = [["🔔 shopping line"], ["🛒 Sales queue"]]
markup = ReplyKeyboardMarkup(key, one_time_keyboard=True, resize_keyboard=True)
update.reply_text('Select', reply_markup=markup)
if update.message.text == '🔔 shopping line':
key = [["menu"]]
markup = ReplyKeyboardMarkup(key, resize_keyboard=True)
list = ["saba", "vmelate", "folad", "shasta", "zobe"]
for i in list:
if update.message.text!="🔔 shopping line":
break
update.message.reply_text('{}shopping line ✅'.format(i), reply_markup=markup)
time.sleep(random.randrange(1, 4))
updater.dispatcher.add_handler(MessageHandler(Filters.text, callback_menu))

Related

pytelegrambotapi callbackquery not responding

i have this code for the message:
#FBot.message_handler(commands=["spy"])
def SpyInit(message):
spyInstance = game.Spy(1, message)
markup = types.InlineKeyboardMarkup()
startButton = types.InlineKeyboardButton("start", callback_data=spyInstance.id.id)
markup.add(startButton)
message = FBot.reply_to(message, "reply on this message to be added to the game", reply_markup = markup)
SpyList.append(spyInstance)
and this:
#FBot.callback_query_handler(func=lambda call : True)
def callback_query(call):
print(call.data)
for instance in SpyList:
if call.data == instance.id.id:
instance.Start()
Spy = instance
for player in Spy.PlayerList:
if Spy.spy == player:
FBot.send_message(player.id, "you are the spy")
else:
FBot.send_message(player.id, Spy.word)
the problem is, i get the first message with the start button but clicking the button does nothing.

PyTelegramBotApi - how to stop one function if other function is running?

I am trying to do an optional input, and have this code
bot.send_chat_action(message.from_user.id, 'typing')
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Лечу только в одну сторону", callback_data="one_way"))
msg = bot.send_message(message.from_user.id, '✅Хорошо. Теперь введите дату возвращения:', reply_markup=markup)
bot.register_next_step_handler(msg, get_return_date)
This code sends user a message with button to skip this step, and registers function get_return_date(), that waits for a date value. Message
And if user clicks the button, query handler register another function get_adults(), that waits for numeric value:
#bot.callback_query_handler(func=lambda call: call.data == "one_way")
def is_one_way(call):
msg = bot.send_message(call.from_user.id,
'✅Хорошо. Сколько взрослых (пассажиров старше 12-ти лет на момент полёта) полетят 🤵👩‍💼?')
bot.register_next_step_handler(msg, get_adults)
return
And, trouble is that - if user clicks the button to skip, both get_return_date() and get_adults() are waiting for a value and work at one time:
Problem
Any ideas what should i do?
You can do this:
bot.send_chat_action(message.from_user.id, 'typing')
msg = bot.send_message(message.from_user.id, '✅Хорошо. Теперь введите дату возвращения: (you can skip this passage with /skip)')
bot.register_next_step_handler(msg, get_return_date)
def get_retourn_date(message):
if message.text == '/skip':
get_adults()
return
# write here the actual function code
i use query callbacks and i put this func at the begining of the callback:
bot.clear_step_handler_by_chat_id(call.message.chat.id)
u can use it like this
def gen_markup():
markup = InlineKeyboardMarkup()
markup.row_width = 1
markup.add(InlineKeyboardButton("Button 1", callback_data="one"),
InlineKeyboardButton("Button 2", callback_data="two"))
def ButtonOneFunc(message):
#do whatever u want here
def ButtonTwoFunc(message):
#do whatever u want here
#bot.callback_query_handler(func=lambda call: True)
def callback_query(call):
bot.clear_step_handler_by_chat_id(call.message.chat.id)
if call.data == "one":
sent= bot.reply_to(call.message, "This is Button 1")
bot.register_next_step_handler(sent, ButtonOneFunc)
elif call.data == "two":
sent= bot.reply_to(call.message, "This is Button 2")
bot.register_next_step_handler(sent, ButtonTwoFunc)
what will happen here is, whenever the user will click a button, it will clear all next_register_handler that were open
and then enter the new call.data and set the handler which the user clicked on

Is it available to wait inline button push or text message simultaneously in Telethon conversation?

Is it available to wait inline button push or text message simultaneously in Telethon conversation?
async with bot.conversation(chat_id) as conv:
buttons = [[Button.inline('Yes'), Button.inline('No')]]
conv.send_message('To be or not no be? Answer yes|no, or write your own opinion', buttons=buttons)
#This way we can wait for button press
def press_event(user_id):
return events.CallbackQuery(func=lambda e: e.sender_id == user_id)
press = await conv.wait_event(press_event(sender_id))
#...and this way we can wait for text message
response = await conv.get_response()
#And how can we wait for press event OR text message simultaneously?
So, here is the solution (thanks to Lonami)
#bot.on(events.NewMessage(pattern='/test'))
async def worklogs(event):
chat_id = event.message.chat.id
sender = await event.get_sender()
sender_id = sender.id
async with bot.conversation(chat_id) as conv:
def my_press_event(user_id):
return events.CallbackQuery(func=lambda e: e.sender_id == user_id)
buttons = [[Button.inline('Yes'), Button.inline('No')]]
await conv.send_message('To be or not no be? Answer yes|no, or write your own opinion', buttons=buttons)
tasks = [conv.wait_event(my_press_event(sender_id)), conv.get_response()]
done, pendind = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
event = done.pop().result()
if type(event) is events.callbackquery.CallbackQuery.Event:
selected = event.data.decode('utf-8')
print(f'Got button: "{selected}"')
elif type(event) is tl.patched.Message:
message = event.text
print(f'Got text message: "{message}"')

Updating Values in PySimpleGUI

I have a bot that fetches data from a website through selenium and I want to plot that data on a GUI. Bot sends Email and Notifications as well, I need someway to change value of real_email and real_noti Live, anytime.
Whole BOT Code is in a while True: loop.
Issue that I am having right now is, I was thinking of adding my BOT CODE and pysimplegui in the same while loop but the program stops at event, values = window.read() for input and will not go further input is passed.
Here is the Demo Code.
import PySimpleGUI as sg
sg.theme('DarkAmber') # Keep things interesting for your users
elem = sg.Text('Email and Notfication ON', key='-TEXT-')
layout = [[elem],
[sg.Input(key='-IN-')],
[sg.Input(key='-IN')],
[sg.Button('Ok'), sg.Exit()]]
window = sg.Window('Window that stays open', layout)
real_email = "On"
real_noti = "On"
while True: # The Event Loop
event, values = window.read()
email = values['-IN-']
notification = values['-IN']
if email == "On":
real_email = "On"
elif email == "Off":
real_email = "Off"
if notification == "On":
real_noti = "On"
elif notification =="Off":
real_noti = "Off"
if event in (None, 'Exit'):
break
print("Testing Print Value After .read()")
window.close()
I just want to change these 2 values in this loop. Maybe a way to use Checkbox or Only Buttons?
You have to set enable_event=True in the sg.Input(key='-IN-') will be sg.Input(key='-IN-', enable_event=True)

How can I create an asynchronous program with urwid and asyncio?

I want to build a chatroom with aiortc. Frist of all, I want to build a mockup with urwid as cli and asyncio.
The urwid part is already running fine, user input is possible. I know want to run a coroutine that generates random text and works as chat clients texting in that chatroom.
I have tried to run my urwid function with the mainloop as an asyncio coroutine but without success.
I don't know how to integrate an asynchronous function into my urwid mainloop.
def unhandled(key):
"""
functin to handle input
"""
global TEXT_INPUT
global lw_user_input
global lw_chatroom
global listbox_chatroom
if not isinstance(key, tuple):
if key == 'enter':
del lw_user_input[-1]
# create widegt and fill with user input
lw_chatroom.append(widget)
TEXT_INPUT = ""
listbox_chatroom.set_focus(len(lw_chatroom)-1, 'above')
elif key == 'esc':
raise urwid.ExitMainLoop()
elif key == 'backspace':
if len(lw_user_input) > 0:
user_input = lw_user_input[0].get_text()[0]
user_input = user_input[:-1]
del lw_user_input[-1]
TEXT_INPUT = user_input
lw_user_input.append(urwid.Text(TEXT_INPUT))
else:
TEXT_INPUT += key # repr(key)
if len(lw_user_input) > 0:
del lw_user_input[-1]
lw_user_input.append(urwid.Text(TEXT_INPUT))
else:
lw_user_input.append(urwid.Text(key))
def generate_output():
global lw_chatroom
global listbox_chatroom
while True:
# generate text and widgets and post with delay
lw_chatroom.append(chat_widget)
listbox_chatroom.set_focus(len(lw_chatroom)-1, 'above')
def create_cli():
# generate all widgets
uloop = urwid.MainLoop(frame, palette, screen,
unhandled_input=unhandled)
uloop.start()
if __name__ == '__main__':
create_cli()
I want to run generate_output() and unhandled(key) asynchronously. I have no idea how to.
Ok, I figured it out.
It is as simple as this:
aloop = asyncio.get_event_loop()
ev_loop = urwid.AsyncioEventLoop(loop=aloop)
loop = urwid.MainLoop(frame, palette, screen,
unhandled_input=unhandled, event_loop=ev_loop)
aloop.create_task(generate_output())
loop.run()

Categories

Resources