【问题标题】:subprocess not working after onefile pyinstaller even with stdout/stdin defined即使定义了标准输出/标准输入,子进程在 onefile pyinstaller 之后也不起作用
【发布时间】:2021-09-03 14:54:12
【问题描述】:

我有一个带有文本框和运行按钮的 tkinter GUI。按下运行按钮将其变为黄色并启动打印几个数字的子程序。子例程的文本输出被重定向到 GUI 文本框。但是,在使用 pyinstaller 创建独立的可执行文件后,它不再起作用。按下运行按钮似乎不会启动子进程。它确实变成黄色,但文本框中没有出现任何文本,并且似乎启动了主程序的另一个实例 - 大约 10 秒后出现第二个 GUI,这是出现初始 GUI 所需的时间。运行按钮在初始 GUI 上保持黄色。

我在网上看到了一些关于其他人在 pyinstaller 之后没有运行子进程的问题,但大多数解决方案似乎是确保 stdout、stdin 设置为我拥有的 subprocess.PIPE,所以我有点不知所措,下一步该尝试什么。

我正在用这个创建我的独立:

pyinstaller --onefile simpleGUI.py

我的子进程文件,testsubprocess.py 是:

import time

for i in range(3):
    print("%d.%d" % divmod(i, 10))
    time.sleep(0.5)

我的主要 GUI 文件 simpleGUI.py 是:

import sys
import subprocess
from threading import Thread
import tkinter as tk
from queue import Queue, Empty


def iter_except(function, exception):
    try:
        while True:
            yield function()
    except exception:
        return


class DisplaySubprocessOutputDemo:
    def __init__(self, root):
        self.root = root

        width=600
        height=350
        xloc=0
        yloc=10
        self.root.geometry('%dx%d+%d+%d' % (width, height, xloc, yloc))

        self.statustext = tk.Text(self.root, height=4, width=30)
        self.statustext.grid(row=3, column=1)

        self.startbutton = tk.Button(self.root, text = 'Start', command=self.startprocess, bg='green', activebackground = 'orange')
        self.startbutton.config(height = 2, width = 15)
        self.startbutton.grid(row = 5, column=0,sticky='E')
        self.startbuttonpresses = 0
        
        exitbutton = tk.Button(self.root, text = 'Exit', command=self.quit, bg='red')
        exitbutton.config(height = 2, width = 15)
        exitbutton.grid(row = 5, column=4, sticky='E')
        
        
    def startprocess(self):    
        self.startbuttonpresses = self.startbuttonpresses+1
        
        if self.startbuttonpresses == 1:
            
            self.startbutton.configure(bg='yellow')
            self.startbutton.configure(text='Stop')
         
            self.process = subprocess.Popen([sys.executable, "-u", "testsubprocess.py"], shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
    
            q = Queue(maxsize=1024)  
            t = Thread(target=self.reader_thread, args=[q])
            t.daemon = True 
            t.start()
    
            self.updatetext(q) 
            
        else:
            self.startbuttonpresses = 0
            self.process.kill()
            self.startbutton.configure(bg='green')
            self.startbutton.configure(text='Start')
            

    def reader_thread(self, q):
        try:
            with self.process.stdout as pipe:
                for line in iter(pipe.readline, b''):
                    q.put(line)
        finally:
            q.put(None)


    def updatetext(self, q):
        for line in iter_except(q.get_nowait, Empty): # display all content
            if line is None:
                self.startbuttonpresses = 0
                self.startbutton.configure(bg='green')
                self.startbutton.configure(text='Start')
                
                return
            else:
                self.statustext.insert(tk.END, line)

        self.root.after(400, self.updatetext, q) 


    def quit(self):
        try:
            self.process.kill() 
        except Exception:
            pass
        self.root.destroy()


root = tk.Tk()
app = DisplaySubprocessOutputDemo(root)
root.protocol("WM_DELETE_WINDOW", app.quit)
root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
root.mainloop()

【问题讨论】:

  • Popen调试标准输出、标准错误、返回码。可能在当前工作目录中找不到testsubprocess.py
  • 我正在从 Anaconda 提示符运行我的可执行文件以尝试获取一些错误消息,但我什么也没得到 - 无论是在 GUI 文本框中,还是在 Anaconda 提示符窗口中。我需要做些什么来显示错误消息吗?
  • 我也尝试过将 testsubprocess.py 文件显式添加到构建中:pyinstaller --onefile --add-data "testsubprocess.py;." simpleGUI.py,但我得到了相同的结果

标签: python tkinter subprocess pyinstaller stdout


【解决方案1】:

当使用 PyInstaller 执行进程时,sys.executable 指向创建的 exe 文件,而不是像解释器中那样指向 python.exe,因此 Popen 将无法工作。

您可以尝试为 testsubprocess.py 创建另一个可执行文件并将 Popen 指向它或使用多处理(如果您使用 https://docs.python.org/3/library/multiprocessing.html#multiprocessing.freeze_support,请不要忘记使用 freeze_support)

【讨论】:

  • 是的 - 就是这样!我用我的 python.exe 的路径替换了 sys.executable,它现在可以工作了。我会查找多处理。非常感谢!我还没有足够的分数,我会赞成你的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
  • 2012-03-13
  • 2019-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多