I have two scripts:
Processor_child.py: Its purpose is to perform a number of data analysis and cleaning operations. This must perform the same operations when run alone (without Tkinter_parent.py) as it does when packaged into a GUI with Tkinter_parent.py.
Tkinter_parent.py: Its purpose is to provide a GUI for those who can't use Processor_child directly.
Within Processor_child, there are for
loops that ask the user for input on each iteration. These prompts need to appear in the Tkinter app, accept the input, and send it back to Processor_child.
The code below does this, raising an Entry
field whenever there's data in the Pipe
(added by the loop). However, it often seems to 'freeze', getting stuck loading and not progressing through the code. Sometimes, it runs perfectly as intended. (No changes in the code in these instances.)
How can I resolve this / make it more stable? I've commented below where the 'freeze' is happening.
Tkinter_parent.py:
### Tkinter_parent.py ###
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter import ttk
from multiprocessing import Process, Pipe
import pandas as pd
import Processor_child
import time
class GUI:
def __init__(self, master):
self.master = master
def gui_input(message, a_pipe = None):
def input_done(event=None):
entry.pack_forget()
input_label.pack_forget()
submit_button.pack_forget()
a_pipe.send(entry.get())
next_one(a_pipe)
entry = Entry(frame)
input_label = ttk.Label(frame, text=message)
entry.bind("<Return>", input_done)
submit_button = ttk.Button(frame, text="Submit", command=input_done)
input_label.pack()
entry.pack()
submit_button.pack()
def file_select():
dataset_path = askopenfilename()
if __name__ == '__main__':
pipe1, pipe2 = Pipe()
some_vars = ['a var', 'another var']
a_df = pd.read_csv(dataset_path)
p_review = Process(target=Processor_child.review_with_user, args=(some_vars, a_df, pipe2))
p_review.start()
gui_input(pipe1.recv(), pipe1)
#time.sleep(1)
def next_one(pipe1):
while pipe1.poll() != True: ### CAUSES CONSTANT LOADING WITHOUT PROGRESSION
time.sleep(0.1)
gui_input(pipe1.recv(), pipe1)
if __name__ == '__main__':
root = Tk()
my_gui = GUI(root)
root.style = ttk.Style()
root.style.configure('my.TButton')
root.style.configure('my.TLabel')
canvas = Canvas(root)
frame = Frame(canvas)
frame.place()
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((45,50), window=frame, anchor="nw")
ttk.Button(frame, text="Select", command=file_select).pack()
root.mainloop()
And processor_child:
### processor_child.py ###
import pandas as pd
from multiprocessing import *
import time
def smart_print(message, a_pipe = None):
if __name__ == "__main__":
print(message)
else:
a_pipe.send(message)
def review_with_user(var_names, dataset, a_pipe = None):
affirmed = []
review_message = 'Yes or no?'
if __name__ == "__main__":
review_response = input(review_message)
else:
smart_print(review_message, a_pipe)
while a_pipe.poll() != True:
time.sleep(0.1)
review_response = a_pipe.recv()
if review_response in ['Yes', 'yes']:
for v in dataset.columns:
smart_print(dataset[v].dropna(), a_pipe)
if __name__ == "__main__":
local_response = input(review_message)
else:
while a_pipe.poll() != True:
time.sleep(0.1)
local_response = a_pipe.recv()
if local_response in ['Yes', 'yes']:
affirmed.append(v)
smart_print(affirmed, a_pipe)
if __name__ == "__main__":
var_names = ['var1', 'var2']
df = pd.read_csv('dummy.csv')
review_with_user(var_names, df)
This is related to the broader SO question How can I implement an input
method in a Tkinter parent script, with the displayed prompt and return value being sent back to a child script?, and comes from a posted, but non-functional, solution there.
As of Oct 23, 2017 there is still not a solution to this.