Created a simple GUI, one button, and one text widget. I want an external python file to run by pressing the button and its output to be displayed in the text widget.
The external file, which simply prints words from a list one word to a line until completed, runs properly with no errors and its output goes to the console. When I press the button though I get the console which I don't want and instead of output there is only a blinking cursor.
The console stays up for the approximate length of time to operate completely, there are time delays involved, so I know it is executing the file, but at the same time the console comes up an error appears in the shell.
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\Lou\AppData\Local\Programs\Python\Python313\Lib\tkinter\__init__.py", line 2068, in __call__ return self.func(*args) ~~~~~~~~~^^^^^^^ File "C:\Users\Lou\Desktop\Python Development\Python Programs\8902A Op-Ver\Module Tester.py", line 18, in btn_click line = subprocess.stdout.readline().decode() ^^^^^^^^^^^^^^^^^ AttributeError: module 'subprocess' has no attribute 'stdout'
The gui code:
import tkinter as tk
import subprocess
import sys, inspect
from subprocess import Popen
root = tk.Tk()
i = tk.PhotoImage(width=1, height=1)
# Title and GUI Size
root.title('Module Tester')
root.geometry("500x300")
# Button function
def btn_click():
btn_click.path = "Test Modules/Test Module 1.py"
Popen(["python", btn_click.path], stdout = subprocess.PIPE)
while True:
line = subprocess.stdout.readline().decode()
if not line:
break
output_box.insert(tk.END, line)
output_box = tk.Text(root, bd = 1, bg = "#3c3d3d", fg = '#7bfce9',
insertbackground='white', font = ("Segoe UI", 11), height = 5, width = 34)
output_box.place(x = 171, y = 167)
# Button
btn1_button = tk.Button(root, image=i, compound='c', width=115, height=20, bd = 1, bg = "#232124", fg = "#a571e5", activebackground="#a571e5", activeforeground="#232124", text = "Test Module 1", font = ("Segoe UI", 11), padx=0, pady=0, command=btn_click)
btn1_button.place(x = 10, y = 20)
root.mainloop()
I understand I have created a function that is calling on my external file and is supposed to redirect the output of my external file and uses a sub process to convert it from streamed output to a python string and I have defined a place for the output to go. I'm not sure what else is happening as I am still fairly new to coding in python and don't have a grasp on all the details yet.
Created a simple GUI, one button, and one text widget. I want an external python file to run by pressing the button and its output to be displayed in the text widget.
The external file, which simply prints words from a list one word to a line until completed, runs properly with no errors and its output goes to the console. When I press the button though I get the console which I don't want and instead of output there is only a blinking cursor.
The console stays up for the approximate length of time to operate completely, there are time delays involved, so I know it is executing the file, but at the same time the console comes up an error appears in the shell.
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\Lou\AppData\Local\Programs\Python\Python313\Lib\tkinter\__init__.py", line 2068, in __call__ return self.func(*args) ~~~~~~~~~^^^^^^^ File "C:\Users\Lou\Desktop\Python Development\Python Programs\8902A Op-Ver\Module Tester.py", line 18, in btn_click line = subprocess.stdout.readline().decode() ^^^^^^^^^^^^^^^^^ AttributeError: module 'subprocess' has no attribute 'stdout'
The gui code:
import tkinter as tk
import subprocess
import sys, inspect
from subprocess import Popen
root = tk.Tk()
i = tk.PhotoImage(width=1, height=1)
# Title and GUI Size
root.title('Module Tester')
root.geometry("500x300")
# Button function
def btn_click():
btn_click.path = "Test Modules/Test Module 1.py"
Popen(["python", btn_click.path], stdout = subprocess.PIPE)
while True:
line = subprocess.stdout.readline().decode()
if not line:
break
output_box.insert(tk.END, line)
output_box = tk.Text(root, bd = 1, bg = "#3c3d3d", fg = '#7bfce9',
insertbackground='white', font = ("Segoe UI", 11), height = 5, width = 34)
output_box.place(x = 171, y = 167)
# Button
btn1_button = tk.Button(root, image=i, compound='c', width=115, height=20, bd = 1, bg = "#232124", fg = "#a571e5", activebackground="#a571e5", activeforeground="#232124", text = "Test Module 1", font = ("Segoe UI", 11), padx=0, pady=0, command=btn_click)
btn1_button.place(x = 10, y = 20)
root.mainloop()
I understand I have created a function that is calling on my external file and is supposed to redirect the output of my external file and uses a sub process to convert it from streamed output to a python string and I have defined a place for the output to go. I'm not sure what else is happening as I am still fairly new to coding in python and don't have a grasp on all the details yet.
You are trying to access the stdout attribute of the subprocess module itself, which doesn't exist. Here is what you should do to capture the output.
btn_click.path = "Test Modules/Test Module 1.py"
process = Popen(["python", btn_click.path], stdout = subprocess.PIPE)
output, error = process.communicate() # reads the output from the pipe
output = output.decode('utf-8') # output is a string
The subprocess.PIPE
is used to redirect the subprocess output to a pipe and them the process.communicate()
reads the output from the pipe.
That said I think you should use the subprocess.run
to capture the output.
btn_click.path = "Test Modules/Test Module 1.py"
result = subprocess.run(["python", btn_click.path], capture_output=True)
output = result.stdout.decode('utf-8') # output is a string
You need to call .stdout.readline().decode()
on the object returned by subprocess.Popen()
.
Also it is better to:
python
to use unbuffered stdout and stderr streamsstderr=subprocess.STDOUT
to redirect stderr
to stdout
in order to capture any error messages as wellBelow is the updated btn_click()
:
from subprocess import Popen, PIPE, STDOUT
...
def btn_click():
btn_click.path = "Test Modules/Test Module 1.py"
# added "-u" when executing python
# added stderr=STDOUT to redirect stderr to stdout
# store the return object of Popen()
proc = Popen(["python", "-u", btn_click.path], stdout=PIPE, stderr=STDOUT)
line = proc.stdout.readline().decode()
while line:
output_box.insert(tk.END, line)
output_box.see(tk.END)
output_box.update()
line = proc.stdout.readline().decode()
# show completion
output_box.insert(tk.END, "----- end -----")
output_box.see(tk.END)