首页 > 解决方案 > Python subproccess.run 不适用于 Pyinstaller

问题描述

考虑以下名为 test.py 的 python (3.9) 脚本:

import sys
import os
import subprocess
from pathlib import Path

# This is for pyinstaller (as main_dir = sys.path[0] won't work)
if getattr(sys, 'frozen', False):
    main_dir = os.path.dirname(sys.executable)
else:
    main_dir = os.path.dirname(os.path.abspath(__file__))

processes_dir = Path(main_dir, "processes")
outfile = Path(main_dir, "output.txt")

# Initialize the output text file
with open(outfile, 'w') as f:
    f.write('')

# This calls A1.py (see below)
result = subprocess.run([sys.executable, Path(processes_dir, "A1.py")], input="1\n2", capture_output=True, text=True)

# If an error is raised, it's written to output.txt; stdout is written to output.txt
if result.stderr:
    with open(outfile, 'a') as f:
        f.write("{0}\n\n".format(result.stderr))
else:
    with open(outfile, 'a') as f:
        f.write("{0}\n\n".format(result.stdout))

subprocess.run 调用以下简单脚本:

x1 = int(input())
x2 = int(input())
print(x1+x2)

这运行得很好。我正在尝试研究如何使用 Pyinstaller 将其转换为可执行文件 (.exe)。在适当的目录中,我运行:

pyinstaller --onefile test.py

这将成功构建 test.exe。当我运行 test.exe(从 cmd 或双击文件)时,它打开时没有错误,产生一个空的 output.txt,然后只是无限期地挂起。看来 subprocess.run 无法与 pyinstaller 一起正常工作。让 test.exe 与 pyinstaller 一起工作的任何想法/建议?

标签: pythonpython-3.xsubprocesspyinstaller

解决方案


这里发生的情况是,当脚本未编译时,sys.executable返回python可执行文件 ( C:\Users\randomuser\AppData\Local\Programs\Python38),但在编译代码时,sys.executable 返回您创建的 .exe 文件。因此,您的 .exe 文件会调用自己,无限次地再次调用自己,哈哈。

您可以通过两种不同(简单)的方式解决此问题:

  1. (如果您想分发 exe 文件,则不太推荐,因为它取决于 python 安装):
    替换sys.executable'python'. 这将确保脚本使用 Python 执行,而不是使用您自己的 .exe 文件(如果已编译):

     result = subprocess.run(['python', Path(processes_dir, "A1.py")], input="1\n2", capture_output=True, text=True)
    
  2. 您可以导入A1.py脚本(确保脚本与可执行文件位于同一文件夹中,并使主代码位于名为 main 的函数中,将结果作为字符串返回):

然后,您将能够运行import A1,并调用主程序 running A1.main()

import sys
import os
import subprocess
import A1
from pathlib import Path

# This is for pyinstaller (as main_dir = sys.path[0] won't work)
if getattr(sys, 'frozen', False):
    main_dir = os.path.dirname(sys.executable)
else:
    main_dir = os.path.dirname(os.path.abspath(__file__))

processes_dir = Path(main_dir, "processes")
outfile = Path(main_dir, "output.txt")

# Initialize the output text file
with open(outfile, 'w') as f:
    f.write('')

# This calls A1.py (see below)
result = A1.main()

# The output is written into output.txt.

with open(outfile, 'a') as f:
    f.write("{0}\n\n".format(result))
          

您可以考虑使用 try-except 子句和 traceback 模块捕获错误回溯

pyinstaller 命令应该是:pyinstaller --onefile test.py --add-data "A1.py;."


推荐阅读