Related
i try to sequence some actions in urwid
I made a timer which run in background and communicate with the mainprocess
like this:
from multiprocessing import Process, Pipe
import time
import urwid
def show_or_exit(key):
if key in ('q', 'Q'):
raise urwid.ExitMainLoop()
class midiloop(urwid.Frame):
def __init__(self):
self.message = urwid.Text('Press Space', align='center')
self.filler = urwid.Filler(self.message, "middle")
super().__init__(urwid.Frame(self.filler))
def keypress(self, size, key):
if key == " ":
self.seq()
else:
return key
def timer(self,conn):
x = 0
while True:
if (conn.poll() == False):
pass
else:
z = conn.recv()
if (z == "kill"):
return()
conn.send(x)
x+=1
time.sleep(0.05)
def seq(self):
self.parent_conn, self.child_conn = Pipe()
self.p = Process(target=self.timer, args=(self.child_conn,))
self.p.start()
while True:
if (self.parent_conn.poll(None)):
self.y = self.parent_conn.recv()
self.message.set_text(str(self.y))
loop.draw_screen()
if ( self.y > 100 ):
self.parent_conn.send("kill")
self.message.set_text("Press Space")
return()
if __name__ == '__main__':
midiloop = midiloop()
loop = urwid.MainLoop(midiloop, unhandled_input=show_or_exit, handle_mouse=True)
loop.run()
The problem is i'm blocking urwid mainloop with while True:
So anyone can give me a solution to listen for key Q to quit the program before it reachs the end of the loop for example and more generally to interact with urwid and communicate with the subprocess
It seems to be rather complicated to combine multiprocessing and urwid.
Since you're using a timer and your class is called midiloop, I'm going to guess that maybe you want to implement a mini sequencer.
One possible way of implementing that is using an asyncio loop instead of urwid's MainLoop, and schedule events with the loop.call_later() function. I've implemented a simple drum machine with that approach in the past, using urwid for drawing the sequencer, asyncio for scheduling the play events and simpleaudio to play. You can see the code for that here: https://github.com/eliasdorneles/kickit
If you still want to implement communication with multiprocessing, I think your best bet is to use urwid.AsyncioEventLoop and the aiopipe helper for duplex communication.
It's not very minimal I'm afraid. However I did spend a day writing this Urwid frontend that starts, stops and communicates with a subprocess.
import os
import sys
from multiprocessing import Process, Pipe, Event
from collections import deque
import urwid
class suppress_stdout_stderr(object):
"""
Supresses the stdout and stderr by piping them to dev null...
The same place I send bad faith replies to my tweets
"""
def __enter__(self):
self.outnull_file = open(os.devnull, 'w')
self.errnull_file = open(os.devnull, 'w')
self.old_stdout_fileno_undup = sys.stdout.fileno()
self.old_stderr_fileno_undup = sys.stderr.fileno()
self.old_stdout_fileno = os.dup(sys.stdout.fileno())
self.old_stderr_fileno = os.dup(sys.stderr.fileno())
self.old_stdout = sys.stdout
self.old_stderr = sys.stderr
os.dup2(self.outnull_file.fileno(), self.old_stdout_fileno_undup)
os.dup2(self.errnull_file.fileno(), self.old_stderr_fileno_undup)
sys.stdout = self.outnull_file
sys.stderr = self.errnull_file
return self
def __exit__(self, *_):
sys.stdout = self.old_stdout
sys.stderr = self.old_stderr
os.dup2(self.old_stdout_fileno, self.old_stdout_fileno_undup)
os.dup2(self.old_stderr_fileno, self.old_stderr_fileno_undup)
os.close(self.old_stdout_fileno)
os.close(self.old_stderr_fileno)
self.outnull_file.close()
self.errnull_file.close()
def subprocess_main(transmit, stop_process):
with suppress_stdout_stderr():
import time
yup = ['yuuuup', 'yuuuuup', 'yeaup', 'yeoop']
nope = ['noooooooe', 'noooope', 'nope', 'nope']
mesg = 0
i = 0
while True:
i = i % len(yup)
if transmit.poll():
mesg = transmit.recv()
if mesg == 'Yup':
transmit.send(yup[i])
if mesg == 'Nope':
transmit.send(nope[i])
if stop_process.wait(0):
break
i += 1
time.sleep(2)
class SubProcess:
def __init__(self, main):
"""
Handles forking, stopping and communication with a subprocess
:param main: subprocess method to run method signature is
def main(transmit, stop_process):
transmit: is a multiprocess Pipe to send data to parent process
stop_process: is multiprocess Event to set when you want the process to exit
"""
self.main = main
self.recv, self.transmit = None, None
self.stop_process = None
self.proc = None
def fork(self):
"""
Forks and starts the subprocess
"""
self.recv, self.transmit = Pipe(duplex=True)
self.stop_process = Event()
self.proc = Process(target=self.main, args=(self.transmit, self.stop_process))
self.proc.start()
def write_pipe(self, item):
self.recv.send(item)
def read_pipe(self):
"""
Reads data sent by the process into a list and returns it
:return:
"""
item = []
if self.recv is not None:
try:
while self.recv.poll():
item += [self.recv.recv()]
except:
pass
return item
def stop(self):
"""
Sets the event to tell the process to exit.
note: this is co-operative multi-tasking, the process must respect the flag or this won't work!
"""
self.stop_process.set()
self.proc.join()
class UrwidFrontend:
def __init__(self, subprocess_main):
"""
Urwid frontend to control the subprocess and display it's output
"""
self.title = 'Urwid Frontend Demo'
self.choices = 'Start Subprocess|Quit'.split('|')
self.response = None
self.item = deque(maxlen=10)
self.event_loop = urwid.SelectEventLoop()
# start the heartbeat
self.event_loop.alarm(0, self.heartbeat)
self.main = urwid.Padding(self.main_menu(), left=2, right=2)
self.top = urwid.Overlay(self.main, urwid.SolidFill(u'\N{MEDIUM SHADE}'),
align='center', width=('relative', 60),
valign='middle', height=('relative', 60),
min_width=20, min_height=9)
self.loop = urwid.MainLoop(self.top, palette=[('reversed', 'standout', ''), ], event_loop=self.event_loop)
self.subprocess = SubProcess(subprocess_main)
def exit_program(self, button):
raise urwid.ExitMainLoop()
def main_menu(self):
body = [urwid.Text(self.title), urwid.Divider()]
for c in self.choices:
button = urwid.Button(c)
urwid.connect_signal(button, 'click', self.handle_button, c)
body.append(urwid.AttrMap(button, None, focus_map='reversed'))
return urwid.ListBox(urwid.SimpleFocusListWalker(body))
def subproc_menu(self):
self.response = urwid.Text('Waiting ...')
body = [self.response, urwid.Divider()]
choices = ['Yup', 'Nope', 'Stop Subprocess']
for c in choices:
button = urwid.Button(c)
urwid.connect_signal(button, 'click', self.handle_button, c)
body.append(urwid.AttrMap(button, None, focus_map='reversed'))
listbox = urwid.ListBox(urwid.SimpleFocusListWalker(body))
return listbox
def update_subproc_menu(self, text):
self.response.set_text(text)
def handle_button(self, button, choice):
if choice == 'Start Subprocess':
self.main.original_widget = self.subproc_menu()
self.subprocess.fork()
self.item = deque(maxlen=10)
if choice == 'Stop Subprocess':
self.subprocess.stop()
self.main.original_widget = self.main_menu()
if choice == 'Quit':
self.exit_program(button)
if choice == 'Yup':
self.subprocess.write_pipe('Yup')
if choice == 'Nope':
self.subprocess.write_pipe('Nope')
def heartbeat(self):
"""
heartbeat that runs 24 times per second
"""
# read from the process
self.item.append(self.subprocess.read_pipe())
# display it
if self.response is not None:
self.update_subproc_menu(['Subprocess started\n', f'{self.item}\n', ])
self.loop.draw_screen()
# set the next beat
self.event_loop.alarm(1 / 24, self.heartbeat)
def run(self):
self.loop.run()
if __name__ == "__main__":
app = UrwidFrontend(subprocess_main)
app.run()
I have created 3 panels in wxpython. One at top. And other 2 panels at bottom in vertical fashion. Panel2 consists of ListControl as list1 and Panel3 consist of ListControl as list2.
I have used wx.ImageList in conjunction with wx.ListCtrl in panel2 and panel3.
I am trying to drag the image from Panel2 to Panel3.
Have used:
self.list1.Bind(wx.EVT_LIST_BEGIN_DRAG, self.OnDragInit, id=self.list1.GetId())
I have used wx.FileDropTarget to define Drop target and wx.BitmapDataObject in the def OnDragInit function.
Piece of code is as follows:
class MyTarget(wx.FileDropTarget):
def __init__(self, object):
wx.FileDropTarget.__init__(self)
self.object = object
def OnDropFiles(self, x, y, filenames):
print(filenames)
return(True)
def OnDragInit(self, event):
text = self.list1.GetBitmap(event.GetIndex())
too = wx.BitmapDataObject(text)
src = wx.DropSource(self.list2)
src.SetData(too)
src.DoDragDrop(True)
Issue: The drop target is not accepting data.
I suspect that you are not setting SetDropTarget.
See here, FileDrTr = MyFileDropTarget(self) and Drop_Place.SetDropTarget(FileDrTr)
import wx
import wx.lib.newevent
drop_event, EVT_DROP_EVENT = wx.lib.newevent.NewEvent()
class MyFileDropTarget(wx.FileDropTarget):
def __init__(self, obj):
wx.FileDropTarget.__init__(self)
self.obj = obj
def OnDropFiles(self, x, y, filename):
#filename is a list of 1 or more files
#here we are restricting it 1 file by only taking the first item of the list
TempTxt = filename[0]
evt = drop_event(data=TempTxt)
wx.PostEvent(self.obj,evt)
return True
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title)
self.InitUI()
self.Center()
def InitUI(self):
panel = wx.Panel(self)
FileDrTr = MyFileDropTarget(self)
font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)
font.SetPointSize(9)
verBox = wx.BoxSizer(wx.VERTICAL)
horBoxOne = wx.BoxSizer(wx.HORIZONTAL)
TextLabel = wx.StaticText(panel, label = 'Drop file here')
TextLabel.SetFont(font)
horBoxOne.Add(TextLabel, flag=wx.RIGHT, border=10)
Drop_Place = wx.TextCtrl(panel)
Drop_Place.SetDropTarget(FileDrTr)
#Bind the drop event listener
self.Bind(EVT_DROP_EVENT, self.LabelTextUpdate)
horBoxOne.Add(Drop_Place, proportion=1)
verBox.Add(horBoxOne, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
verBox.Add((-1, 10))
horBoxTwo = wx.BoxSizer(wx.HORIZONTAL)
self.NewText = wx.StaticText(panel, label = 'Path will be')
horBoxTwo.Add(self.NewText, flag=wx.RIGHT, border=5)
verBox.Add(horBoxTwo, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
panel.SetSizer(verBox)
def LabelTextUpdate(self, event):
txt = event.data
self.NewText.SetLabel(txt)
def main():
app = wx.App()
ex = Example(None, title = 'drop and see file path')
ex.Show()
app.MainLoop()
if __name__ == '__main__':
main()
Note the target is the textctrl, dropping a file on the panel will achieve nothing, whilst dropping on the target (the textctrl called Drop_Place) will activate the event.
I was trying to make my code a little cleaner by using cogs but it doesn't seem to work. When I do +balance this error comes up: Ignoring exception in command None: discord.ext.commands.errors.CommandNotFound: Command "balance" is not found: Here's the code part in main.py:
for file in os.listdir("./cogs"): # lists all the cog files inside the cog folder.
if file.endswith(".py"): # It gets all the cogs that ends with a ".py".
name = file[:-3] # It gets the name of the file removing the ".py"
bot.load_extension(f"cogs.{name}") # This loads the cog.
And from the balance file:
bot = commands.Bot(command_prefix='+')
class Balance(commands.Cog):
def __init__(self, client):
self.bot = bot
#commands.command(aliases = ["bal"])
async def balance(self, ctx):
await open_account(ctx.author)
user = ctx.author
users = await get_bank_data()
wallet_amt = users[str(user.id)]["wallet"]
#bank_amt = users[str(user.id)]["bank"]
em = discord.Embed(title = f"{ctx.author.name}'s balance",color = (0x95a5a6), description = f"{wallet_amt} dogecoins")
#em.add_field(name = "Bank balance",value = bank_amt)
await ctx.send(embed = em)
async def open_account(user):
users = await get_bank_data()
if str(user.id) in users:
return False
else:
users[str(user.id)] = {}
users[str(user.id)]["wallet"] = 250
users[str(user.id)]["bank"] = 0
with open("mainbank.json","w") as f:
json.dump(users,f)
return True
async def get_bank_data():
with open("mainbank.json","r") as f:
users = json.load(f)
return users
async def update_bank(user,change = 0,mode = "wallet"):
users = await get_bank_data()
users[str(user.id)][mode] += change
with open("mainbank.json","w") as f:
json.dump(users,f)
return True
def setup(bot):
bot.add_cog(Balance(bot))
I'm new to coding and cogs especially so if anyone knows how to fix this, please help me.
I can't tell if the commands and functions you're showing are inside the class or not. Also, why are you creating a new Bot instance, and why does your init function take an argument called client and then set self.bot to bot?
Try replacing client in your init function with bot, or vice versa.
Do you get any errors when you try to run your main file?
As seen in the example above, a mixture of the Label objects on the left column or Entry objects on the right column are not shown when scrolling too fast.
If I click on the scrollbar and drag quickly it can look as bad as this. If I use the wheel on the mouse to scroll slowly it is typically fine, though sometimes a line will get missed no matter how slowly I scroll. For reference, it seems to always be the same line(s) that do not show when scrolling slowly.
Changing tabs back and forth causes everything to draw properly again. On Linux, everything works perfectly. But this needs to work on Windows as well.
Not sure if it matters, but each line is a Label and Entry inside of a Frame inside of a Canvas that, along with a Scrollbar, is inside of a Frame. Each of those top Frames is a "page" in a Notebook to provide the tabs shown on top.
And finally some questions. Is there a button I can add to force this to redraw without destroying and recreating it? Or possibly something I can add when creating these objects to force them to redraw when moved?
Sample code upon request:
#!/usr/bin/env python3
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText
class WriteableEntry(Label):
def __init__(self, name, value, *args, **kwargs):
#~ self.ip = ip
#~ self.ping_results = []
super(WriteableEntry, self).__init__(*args, **kwargs)
self.label = name
self.init_value = value
self.written_value = ''
self.field_name = Label(self, justify="left", text=name, width=25)
self.field_value = Entry(self, justify='left', width=60)
self.field_value.insert(END, value)
self.field_name.pack(side=LEFT)
self.field_value.pack(side=LEFT)
class InfoFrame(Frame):
def __init__(self, *args, **kwargs):
super(InfoFrame, self).__init__(*args, **kwargs)
self.nb_frame = Frame(self, height=300, width=730)
self.nb_frame.pack_propagate(False)
self.nb = ttk.Notebook(self.nb_frame)
self.nb.pressed_index = None
filler = {}
for x in range(0, 3):
for y in ('a', 'b', 'c', 'd', 'e', 'f', 'g'):
filler.update({"out%d_%s" % (x, y):"nada"})
self.example_dict = {'A':filler, 'B':filler, 'C':filler}
print("E_D:\n", self.example_dict)
for page in sorted(self.example_dict):
print("page:\t", page)
entry_count = len(self.example_dict[page])
# # ## Make new_page to put in nb
new_page = Frame(self.nb)
new_page.pack(fill=BOTH, expand=True)
# # ## Make canvas to put in that new_page
canvas = Canvas(new_page)
scroll = Scrollbar(new_page, command=canvas.yview)
## Orig *27
canvas.config(yscrollcommand=scroll.set, scrollregion=(0,120,120,entry_count * 35))
canvas.pack(side=LEFT, fill=BOTH, expand=True)
scroll.pack(side=RIGHT, fill=Y)
# # ## Make a frame to put in that canvas
canvas_frame = Frame(canvas, bg='white', width=50, height=50)
## Orig +12 *10
canvas.create_window(345, (entry_count + 12) * 13, window=canvas_frame)
for value in sorted(self.example_dict[page]):
print("value:\t", value)
writeable_entry = WriteableEntry(value, self.example_dict[page][value], master=canvas_frame)
writeable_entry.pack(side=TOP)
self.nb.add(new_page, text=page)
self.nb.pack(side=TOP, expand=True, fill="both")
self.nb_frame.pack(side=RIGHT, expand=True, fill=BOTH)
class IPLabel(LabelFrame):
def __init__(self, *args, **kwargs):
super(IPLabel, self).__init__(*args, **kwargs)
self.info_frame = InfoFrame(master=self)
self.info_frame.grid(row=1, columnspan=2, sticky=E + W)
class AvailableApplication(Frame):
def __init__(self, master):
super(AvailableApplication, self).__init__(master)
#~ self.ips = ips
self.grid()
self.grid_propagate(True)
self.ip_widgets = []
self.createWidgets()
def createWidgets(self):
self.ip_frame = Frame(self)
self.ip_widgets = []
ip_widget = IPLabel(master=self.ip_frame)
ip_widget.grid(row=0, column=1, columnspan=4, sticky=E + W)
self.ip_widgets.append(ip_widget)
self.ip_frame.grid(row=1, column=0, columnspan=8)
self.ip_frame.grid_propagate(True)
if __name__ == "__main__":
root = Tk()
root.title("Example Script")
app = AvailableApplication(root)
app.mainloop()
root.destroy()
The main problem is the WriteableEntry. It is not a tk.Label. You can't have sub widgets (a tk.Label and a tk.Entry) of a tk.Label. You also have the wrong layout manager for this work. Maybe also because of the wrong sub widget use. You rely on the wrap behavior of the pack manager. Don't. Use the grid() manager.
For some reason tab C is not visible but that is another problem.
Using Ctrl-Tab I found that there is a third tab but the tab text was the empty string. Adding the tab with
self.nb.add(new_page, text="P"+page)
Made it better visible. I have no idea why the tab name "C" has a special meaning for tkinter
The only possible way to kill the App and window is by using the Close button. So why do you destroy the root window? It is already destroyed.
#!/usr/bin/env python3
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText
class WriteableEntry(object):
def __init__(self, name, value, *args, **kwargs):
#~ self.ip = ip
#~ self.ping_results = []
#super(WriteableEntry, self).__init__(*args, **kwargs)
master = kwargs['master']
row = kwargs['row']
self.label = name
self.init_value = value
self.written_value = ''
self.field_name = Label(master, justify="left", text=name, width=25)
self.field_value = Entry(master, justify='left', width=60)
self.field_value.insert(END, value)
self.field_name.grid(row=row, column=0)
self.field_value.grid(row=row, column=1)
class InfoFrame(Frame):
def __init__(self, *args, **kwargs):
super(InfoFrame, self).__init__(*args, **kwargs)
self.nb_frame = Frame(self, height=300, width=730)
self.nb_frame.pack_propagate(False)
self.nb = ttk.Notebook(self.nb_frame)
self.nb.pressed_index = None
filler = {}
for x in range(0, 3):
for y in ('a', 'b', 'c', 'd', 'e', 'f', 'g'):
filler.update({"out%d_%s" % (x, y):"nada"})
self.example_dict = {'A':filler, 'B':filler, 'C':filler}
print("E_D:\n", self.example_dict)
for page in sorted(self.example_dict):
print("page:\t", page)
entry_count = len(self.example_dict[page])
# # ## Make new_page to put in nb
new_page = Frame(self.nb)
new_page.pack(fill=BOTH, expand=True)
# # ## Make canvas to put in that new_page
canvas = Canvas(new_page)
scroll = Scrollbar(new_page, command=canvas.yview)
## Orig *27
canvas.config(yscrollcommand=scroll.set, scrollregion=(0,120,120,entry_count * 35))
canvas.pack(side=LEFT, fill=BOTH, expand=True)
scroll.pack(side=RIGHT, fill=Y)
# # ## Make a frame to put in that canvas
canvas_frame = Frame(canvas, bg='white', width=50, height=50)
## Orig +12 *10
canvas.create_window(345, (entry_count + 12) * 13, window=canvas_frame)
for row, value in enumerate(sorted(self.example_dict[page])):
print("value:\t", value)
writeable_entry = WriteableEntry(value, self.example_dict[page][value], master=canvas_frame, row=row)
#writeable_entry.pack(side=TOP)
self.nb.add(new_page, text="P"+page)
self.nb.pack(side=TOP, expand=True, fill="both")
self.nb_frame.pack(side=RIGHT, expand=True, fill=BOTH)
class IPLabel(LabelFrame):
def __init__(self, *args, **kwargs):
super(IPLabel, self).__init__(*args, **kwargs)
self.info_frame = InfoFrame(master=self)
self.info_frame.grid(row=1, columnspan=2, sticky=E + W)
class AvailableApplication(Frame):
def __init__(self, master):
super(AvailableApplication, self).__init__(master)
#~ self.ips = ips
self.grid()
self.grid_propagate(True)
self.ip_widgets = []
self.createWidgets()
def createWidgets(self):
self.ip_frame = Frame(self)
self.ip_widgets = []
ip_widget = IPLabel(master=self.ip_frame)
ip_widget.grid(row=0, column=1, columnspan=4, sticky=E + W)
self.ip_widgets.append(ip_widget)
self.ip_frame.grid(row=1, column=0, columnspan=8)
self.ip_frame.grid_propagate(True)
if __name__ == "__main__":
root = Tk()
root.title("Example Script")
app = AvailableApplication(root)
app.mainloop()
#root.destroy()
this is my form:
class IPTrackerSearchForm(forms.Form):
keyword = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'size':'50'}))
search_in = forms.ChoiceField(required=False, choices=ANY_CHOICE + MODULE_SEARCH_IN_CHOICES)
product = forms.CharField(max_length=64,widget=forms.TextInput(attrs={'size':'50'}))
family = forms.CharField(max_length=64,widget=forms.TextInput(attrs={'size':'50'}))
temp_result = Merlin.objects.values('build').distinct()
result = [(value['build'], value['build']) for value in temp_result]
build = forms.ChoiceField(choices=ANY_CHOICE + result)
circuit_name = forms.CharField(max_length=256,widget=forms.TextInput(attrs={'size':'50'}))
parameterization = forms.CharField(max_length=1024,widget=forms.TextInput(attrs={'size':'50'}))
metric = forms.CharField(max_length=64,widget=forms.TextInput(attrs={'size':'50'}))
show_in_one_page = forms.BooleanField(required=False, label="Show filtered result in one page", widget=forms.CheckboxInput(attrs={'class':'checkbox'}))
def __init__(self, *args, **kwargs):
super(IPTrackerSearchForm, self).__init__(*args, **kwargs)
temp_result = Merlin.objects.values('build').distinct()
self.result = [(value['build'], value['build']) for value in temp_result]
self.build = forms.ChoiceField(choices=ANY_CHOICE + self.result)
print self.result
With the purpose that, each time I refresh the webpage, when have new record to "build" column in database. It should update to the drop down box "build" here but It never update unless restart the server. I use print and see that __init__ detect new record but can not refect to build in Class.
Many thanks
You actually need to update self.fields['build'] instead of self.build.
def __init__(self, *args, **kwargs):
super(IPTrackerSearchForm, self).__init__(*args, **kwargs)
temp_result = Merlin.objects.values('build').distinct()
result = [(value['build'], value['build']) for value in temp_result]
self.fields['build'] = forms.ChoiceField(choices=ANY_CHOICE + result)
print result
Because you're not updating self.fields, you are seeing the result of the query at compile time, not execution.