python-telegram-bot keyboard doesn't appear - python-telegram-bot

I'm trying to make a bot for channel management and the keyboard (channel_markup in the code) for the channel selection doesn't appear. Now this keyboard is hard coded but later I want to introduce a used-based keyboard for channel.
from telegram import ReplyKeyboardMarkup
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters, RegexHandler, ConversationHandler)
from Post import Post
MENU, CHANNEL = range(2)
menu_markup = ReplyKeyboardMarkup([['POST', 'HTML']], one_time_keyboard=True, resize_keyboard=True)
def error(update, context):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, error)
def start(bot, update, user_data):
reply_text = 'Hi!'
update.message.reply_text(reply_text, reply_markup=menu_markup)
return MENU
def new_post(bot, update, user_data):
user_data['post'] = Post()
channel_markup = ReplyKeyboardMarkup([['Test1', 'Test2']],
one_time_keyboard=True, resize_keyboard=True)
update.message.reply_text(text="Select channel",
replyMarkup=channel_markup)
return CHANNEL
def channel_choice(bot, update, user_data):
channel = update.message.text
user_data['post'].channel = channel
update.message.reply_text('Hi', reply_markup=menu_markup)
return MENU
def test_bot(args):
pass
def main():
updater = Updater("TOKEN")
dp = updater.dispatcher
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start, pass_user_data=True)],
states={
MENU: [RegexHandler('^POST$', new_post, pass_user_data=True)],
CHANNEL: [RegexHandler('^Test1$', channel_choice, pass_user_data=True)]
},
fallbacks=[RegexHandler('^fallbacks$', test_bot)])
dp.add_handler(conv_handler)
# log all errors
dp.add_error_handler(error)
# Start the Bot
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()

Replace replyMarkup with reply_markup.

Related

Voila, jupyter and websockets: how to print?

Although the question might seem simple I can't see to find a viable way or anyway of printing the incoming messages from a threaded websocket.
Basically, I've created a jupyterlab notebook that lets me connect to a local websocket server and echo messages sent from a firecamp websocket connection. When running it on a cell (without the run button and run A.start()) I can see the prints but as soon as I hit the run button after restarting the kernal I can't see incoming messages.
Normally I would expect something like:
Function started
Someone said: test 1
Someone said: test 2
In the prints but nothing seems to apperas when hitting the run button.
The main objective is to be able to run the notebook with voila to upload to heroku but I can´t seem to make the prints work. If anybody has a clue or a better idea, I'm all ears.
Thanks in advance.
PD: Code
import ipywidgets as widgets
from IPython.display import Javascript, display
import websocket
import asyncio
import nest_asyncio
import threading
import websocket
import time
import sys
import trace
import logging
from time import sleep
output_box = widgets.Output()
class KThread(threading.Thread):
"""A subclass of threading.Thread, with a kill() method."""
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
"""Start the thread."""
self.__run_backup = self.run
self.run = self.__run
threading.Thread.start(self)
def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
ws.close()
self.killed = True
def on_message(ws, message):
print(message)
def on_open(ws):
ws.send("Connected Test")
def on_close(ws, close_status_code, close_msg):
print("### closed ###")
def on_error(ws, error):
print(error)
#This illustrates running a function in a separate thread. The thread is killed before the function finishes.
def func():
print('Function started')
ws.run_forever()
ws = websocket.WebSocketApp("ws://localhost:7890", on_open=on_open,on_message = on_message, on_close = on_close,on_error = on_error)
A = KThread(target=func)
websocket.enableTrace(True)
run_button = widgets.Button(
description='Run Button',
disabled=False,
button_style='info', # 'success', 'info', 'warning', 'danger' or ''
tooltip='Run button function',
icon='play'
)
def on_run_button_clicked(b):
with output_box:
A.start()
run_button.on_click(on_run_button_clicked)
display(run_button,output_box)
This is the websocket server:
# Importing the relevant libraries
import websockets
import asyncio
# Server data
PORT = 7890
print("Server listening on Port " + str(PORT))
# A set of connected ws clients
connected = set()
# The main behavior function for this server
async def echo(websocket, path):
print("A client just connected")
# Store a copy of the connected client
print(websocket)
connected.add(websocket)
# Handle incoming messages
try:
async for message in websocket:
print("Received message from client: " + message)
# Send a response to all connected clients except sender
for conn in connected:
if conn != websocket:
await conn.send("Someone said: " + message)
# Handle disconnecting clients
except websockets.exceptions.ConnectionClosed as e:
print("A client just disconnected")
finally:
connected.remove(websocket)
# Start the server
start_server = websockets.serve(echo, "localhost", PORT)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

My application on the heroku server stops after running for 1 minute (PYTHON)

My application on the heroku server stops after running for 1 minute. Then it runs and hears commands sent to itself whenever it wants. I was wondering if it could be from the 30-minute limit, but it never worked that long.
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
import commands as c
TOKEN = "--------------"
def main():
updater = Updater(TOKEN, use_context=True)
dp = updater.dispatcher
#my commands
dp.add_handler(CommandHandler("start", c.start_command))
#while I write unknown word that the bot doesnt know
dp.add_handler(MessageHandler(Filters.text, c.wrong_command))
updater.start_polling()
updater.idle()
if __name__ == "__main__":
main()
#commands.py
from telegram.ext import Updater
def start_command(update, context):
message = "hi!"
return update.message.reply_text(message)
def wrong_command(update, context):
message = "/start only"
return update.message.reply_text(message)
requirements.txt
"""
python-telegram-bot
Procfile
web: python main.py
""" There are not many codes in the "signs".

discord.py running a 'commands.group()' sends the help command, when targeting second command

Hard to get the title perfect, but pretty much. Got it hooked up that !!changelog is the main command, this will send a list of all the commands available, but issue I am getting is that. Whenever I run the !!changelog message <text> command, the preset "help" message shows up.
Picture here:
Whenever the message is sent, I just want it to say something like "Your message has been sent"
Here is my code:
#commands.group(invoke_without_command=True)
async def changelog(self, ctx):
await ctx.send('Available Setup Commands: \nSet Channel: <#channel>\nChangelog Message: <message>')
#changelog.command()
async def channel(self, ctx, channel: discord.TextChannel):
if ctx.message.author.guild_permissions.administrator:
db = sqlite3.connect('main.sqlite')
cursor = db.cursor()
cursor.execute(
f'SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}')
result = cursor.fetchone()
if result is None:
sql = ('INSERT INTO main(guild_id, channel_id) VALUES(?,?)')
val = (ctx.guild.id, channel.id)
await ctx.send(f'Channel has been set to {channel.mention}')
elif result is not None:
sql = ('UPDATE main SET channel_id = ? WHERE guild_id = ?')
val = (channel.id, ctx.guild.id)
await ctx.send(f'Channel has been updated to {channel.mention}')
cursor.execute(sql, val)
db.commit()
cursor.close()
db.close()
#changelog.command()
async def message(self, ctx, *, text):
if ctx.message.author.guild_permissions.manage_messages:
est = timezone('EST')
db = sqlite3.connect('main.sqlite')
cursor = db.cursor()
cursor.execute(f'SELECT channel_id FROM main WHERE 1')
channel = cursor.fetchone()
channel_id = self.client.get_channel(int(channel[0]))
message = text.capitalize()
embed = discord.Embed(
title="Changelog", description=f"● {message}", color=0)
embed.set_footer(
text=f'Published: {datetime.now(est).strftime("%Y-%m-%d %H:%M:%S")}')
await channel_id.send(embed=embed)
cursor.close()
db.close()
You can use ctx.invoked_subcommand to check if you are running a subcommand in your group:
async def changelog(self, ctx):
if ctx.invoked_subcommand is None:
await ctx.send('Available Setup Commands: \nSet Channel <#channel>\nChangelog Message: <message>')

Change log level dynamically from asyncio outside module

I need to dynamically change log level without reloading any modules. For this, I am using a combination of asyncio and multiprocessing (both for the bigger program that I am writing).
log_config.py
def setupLogging(log_level=None): # load custom logger
with open(os.path.join(LOG_PATH,'log_config.yaml'), 'rt') as file_:
config = yaml.safe_load(file_.read())
logging.config.dictConfig(config)
logging.Formatter.converter = time.gmtime
if not log_level:
log_level = 'preview'
return logging.getLogger(log_level)
logger=setupLogging() # global var that needs dynamic updation
async def logger_changes(): # socket listener that changes the logger object
global logger
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 9999))
sock.listen()
sock.setblocking(0)
while True:
try:
conn, addr = sock.accept()
data = conn.recv(1024)
conn.send(data)
logger = setupLogging(data.decode('utf8'))
except Exception as e:
pass
await asyncio.sleep(5)
async def logger_handler():
t1 = asyncio.create_task(logger_changes())
await t1
def start_logger():
start_func = asyncio.run(logger_handler())
pLOGGER = Process(name="__startLOGGER__", target=start_logger, daemon=False)
pLOGGER.start()
Main Functionality
import log_config
logger=log_config.logger
async def core_func():
for i in range(10):
logger.debug("sample debug log")
logger.info("sample info log")
logger.warning("Watch out!")
logger.error("Heading for trouble!")
logger.critical("Seriously, do something!")
print("#"*80)
await asyncio.sleep(5)
async def core_func_parent():
t1 = asyncio.create_task(core_func())
await t1
def core_func_handler():
start_func = asyncio.run(core_func_parent())
if __name__=='__main__':
pMODULE = Process(name="__startMODULE__", target=core_func_handler, daemon=False)
pMODULE.start()
Trigger Log Level Change
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.connect(('localhost', 9999))
request = "test"
try:
server.send(request.encode('utf8'))
response = server.recv(255).decode('utf8')
print(response)
except Exception as e:
print(e)
server.close()
Steps
Run main functionality python script. Automatically invoked log_config from inside, starts the socket listener and instantiates the logger object
Run trigger log level change that sends a message to the web socket with the updated logger setting
Challenge
Once I run step 1, the logging level is INFO (which is exactly what I want)
But once I run step 2, I am expecting the logging level to change to DEBUG which is not happening.
Any help is appreciated.

Python 3 Tkinter multiple functions running at once

I have a chat window for the client portion of a chat application that uses Tkinter for the GUI:
import socket
import select
import time
from threading import Thread
from multiprocessing import Process
import sys
from tkinter import *
HOST = "localhost"
PORT = 5678
client_socket = socket.socket()
client_socket.settimeout(2)
try:
client_socket.connect((HOST, PORT))
except:
print("Connection failed.")
sys.exit()
print("Connected to [" + str(HOST) + "," + str(PORT) + "] successfully")
class ChatWindow:
def __init__(self):
form = Tk()
form.minsize(200, 200)
form.resizable(0, 0)
form.title("Chat")
box = Entry(form)
form.bind("<Return>", lambda x: self.sendmessage(self.textbox.get()))
area = Text(form, width=20, height=10)
area.config(state=DISABLED)
area.grid(row=0, column=1, padx=5, pady=5, sticky=W)
box.grid(row=1, column=1, padx=5, pady=5, sticky=W)
self.textbox = box
self.textarea = area
p1 = Process(target=updating)
p1.start()
p2 = Process(target=tryrecvmessage)
p2.start()
def addchat(self, msg, clear=False):
self.textarea.config(state=NORMAL)
self.textarea.insert(END, msg + "\n")
if clear:
# Option to clear text in box on adding
self.textbox.delete(0, END)
self.textarea.see(END)
self.textarea.config(state=DISABLED)
def sendmessage(self, msg):
data = str.encode(msg)
client_socket.send(data)
self.addchat("<You> " + msg, True)
def updating(self):
while True:
form.update()
form.update_idletasks()
time.sleep(0.01)
def tryrecvmessage(self):
while True:
read_sockets, write_sockets, error_sockets = select.select([client_socket], [], [])
for sock in read_sockets:
data = sock.recv(4096)
if data:
self.addchat(data)
else:
self.addchat("Disconnected...")
sys.exit()
if __name__ == "__main__":
window = ChatWindow()
I want the updating() function and the tryrecvmessage() function to run simultaneously, so that the GUI continues to update while the client still receives messages from the server. I've tried using the threading module as well, but I need to have the threads created below where the other functions are defined, but the other functions need to be defined below __init__(). What do I do?
You can attach the functions to the Tk event loop using the after method, as I explained in this question. Essentially the syntax for after goes like this:
after(ms, command = [function object])
What it does is attach the function object passed in as the command argument to the Tk event loop, repeating it each time ms milliseconds has passed.
One caveat here: you would want to remove the while True from the functions as after would be constantly repeating them anyway.

Resources