简体   繁体   English

从使用 pyinstaller 运行单独的 python 脚本的 python 脚本创建 .exe

[英]Creating a .exe from a python script which runs a separate python script using pyinstaller

Short Version:精简版:

I have a series of python scripts that connect together (one .py closes and runs a separate .py).我有一系列连接在一起的 python 脚本(一个 .py 关闭并运行一个单独的 .py)。 This works completely fine when running it through the terminal in VS Code or cmd line.在 VS Code 或 cmd 行中通过终端运行它时,这完全正常。 Once it is in a .exe by pyinstaller, only the first code works and the program closes once it tries to execute a separate .py file.一旦它被 pyinstaller 放在 .exe 中,只有第一个代码起作用,并且程序在尝试执行单独的 .py 文件时关闭。

Details:细节:

All of the separate python files are saved in the same directory.所有单独的python文件都保存在同一目录中。 The first one to open, 'Main.py', has a tkinter interface that allows the user to select which .py script they want to run.第一个打开的“Main.py”有一个 tkinter 界面,允许用户选择他们想要运行的 .py 脚本。 The code then closes the Main window and opens the selected python script using exec(open('chosen .py').read()) .然后代码关闭主窗口并使用exec(open('chosen .py').read())打开选定的 python 脚本。 (This is a simplified version of the initial code but I am having the same issues) (这是初始代码的简化版本,但我遇到了同样的问题)

import tkinter as tk
from tkinter import ttk
from tkinter.constants import W
from tkinter import messagebox as mb

""" Open a window to select which separate script to run"""

root = tk.Tk()
root.title('Selection Window')
root.geometry('300x200')

frame_1 = tk.LabelFrame(root, text='Choose Program')
frame_1.pack()

# Using this function to update on radio button select
def radio_button_get():
    global program_int
    choice = radio_ID.get()
    if(choice == 1):
        program_int = 1
    elif(choice == 2):
        program_int = 2

# Display confirmation popup
def run_script():
    if(program_int == 1):
        select = mb.askokcancel("Confirm", "Run choice 1?")
        if(select == 1):
            root.destroy()
        else:
            return
    if(program_int == 2):
        select = mb.askokcancel("Confirm", "No selection")
        if(select == 1):
            root.destroy()
        else:
            return

# Create radio buttons to select program 
radio_ID = tk.IntVar()
radio_ID.set(2)
program_int = 2     # Set default selection

choice_1 = tk.Radiobutton(frame_1, text='Execute Script 1', variable=radio_ID, value=1, command=radio_button_get)
choice_1.pack()
no_choice = tk.Radiobutton(frame_1, text='No Selection', variable=radio_ID, value=2, command=radio_button_get)
no_choice.pack()

# Button to run the selected code
run_button = ttk.Button(root, text='Run', command=run_script)
run_button.pack()
root.mainloop()

# Execute the other python script 
if(program_int == 1):
    exec(open('Script1.py').read())

The next code is the 'Script1.py' file which 'Main.py' runs at the end.下一个代码是“Main.py”最后运行的“Script1.py”文件。 This is the step which works fine in VS Code and cmd line, but causes the .exe from pyinstaller to close.这是在 VS Code 和 cmd 行中运行良好的步骤,但会导致 pyinstaller 中的 .exe 关闭。

import tkinter as tk
from tkinter import ttk

""" Create this programs GUI window"""

root = tk.Tk()
root.title('Script 1')

def run():
    root.destroy()

label = ttk.Label(root, text='Close to run')
label.pack()
button = ttk.Button(root, text='Close', command=run)
button.pack()

root.mainloop()

""" Do some code stuff here"""

# When above code is done, want to return to the Main.py window
exec(open('Main.py').read())

Each independent .py file have been successfully turned into .exe files with pyinstaller previously.每个独立的 .py 文件之前都已成功使用 pyinstaller 转换为 .exe 文件。 The cmd line command that I am using to execute pyinstaller is pyinstaller 'Main.py' This successfully creates a Main.exe in the dist folder and also includes a build folder.我用来执行 pyinstaller 的 cmd 行命令是pyinstaller 'Main.py'这成功地在 dist 文件夹中创建了一个 Main.exe,还包括一个 build 文件夹。

I have read through pyinstallers documentation, but have not found anything that I believe would be useful in this case.我已经通读了 pyinstallers 文档,但没有找到我认为在这种情况下有用的任何内容。 The nearest issue I could find was importing python scripts as modules in the .spec file options but since the code executes the python script as a separate entity, I don't think this is the fix.我能找到的最近的问题是在 .spec 文件选项中将 python 脚本作为模块导入,但由于代码将 python 脚本作为单独的实体执行,我认为这不是解决方案。

Would the issue be in how the scripts are coded and referencing each other, or with the installation process with pyinstaller?问题是脚本如何编码和相互引用,还是与 pyinstaller 的安装过程有关? If I missed something in the documentation that would explain this issue, please let me know and I will look there!如果我遗漏了文档中可以解释此问题的内容,请告诉我,我会查看!

Any help is greatly appreciated, thank you非常感谢任何帮助,谢谢

We must avoid using the .exec command.我们必须避免使用.exec命令。 It is hacky but unsafe.这是hacky但不安全。 Ref: Running a Python script from another参考:从另一个运行 Python 脚本

Instead use import :而是使用import

# Execute the other python script 
if(program_int == 1):
    import Script1

And here too:这里也是:

# When above code is done, want to return to the Main.py window
import Main

That's it, now use pyinstaller.就是这样,现在使用pyinstaller。


EDIT:编辑:

Why .exe file fails to execute another script, and why exec() is the problem:为什么.exe文件无法执行另一个脚本,以及为什么exec()是问题所在:

According to the documentation:根据文档:

Pyinstaller analyzes your code to discover every other module and library your script needs in order to execute. Pyinstaller 分析您的代码以发现您的脚本执行所需的所有其他模块和库。 Then it collects copies of all those files – including the active Python interpreter!然后它收集所有这些文件的副本——包括活动的 Python 解释器! – and puts them with your script in a single folder, or optionally in a single executable file. – 并将它们与您的脚本放在一个文件夹中,或者可以选择放在一个可执行文件中。

So, when pyinstaller is analyzing & creating the .exe file, it only executes the exec() function that time (so no error thrown while pyinstaller runs), pyinstaller does not import it or copies it to your .exe.因此,当 pyinstaller 分析和创建 .exe 文件时,它只在那个时候执行exec()函数(因此在 pyinstaller 运行时不会抛出错误), pyinstaller 不会导入它或将其复制到您的 .exe。 file , and then after the .exe file is created, upon running it throws error that no such script file exists because it was never compiled into that .exe file. file ,然后在创建 .exe 文件后,在运行时会抛出错误,指出不存在此类脚本文件,因为它从未编译到该 .exe 文件中。

Thus, using import will actually import the script as module, when pyinstaller is executed, and now your .exe file will give no error.因此,当执行 pyinstaller 时,使用import实际上会将脚本作为模块导入,现在您的 .exe 文件将不会出错。

Instead of importing the scripts as modules, for them to be re-executed again and again, import another script as a function in Main.py不是将脚本作为模块导入,而是为了一次又一次地重新执行它们,在 Main.py 中导入另一个脚本作为函数

Also, instead of destroying your Main root window (since you won't be able to open it again unless you create a new window), use .withdraw() to hide it and then .deiconify() to show.此外,不要破坏主根窗口(因为除非创建新窗口,否则您将无法再次打开它), .withdraw()使用.withdraw()隐藏它,然后使用.deiconify()显示。


First, in Script1.py:首先,在 Script1.py 中:

import tkinter as tk
from tkinter import ttk

""" Create this programs GUI window"""
def script1Function(root):      #the main root window is recieved as parameter, since this function is not inside the scope of Main.py's root
    root2 = tk.Tk()             #change the name to root2 to remove any ambiguity
    root2.title('Script 1')

    def run():
        root2.destroy()         #destroy this root2 window
        root.deiconify()        #show the hidden Main root window
    label = ttk.Label(root2, text='Close to run')
    label.pack()
    button = ttk.Button(root2, text='Close', command=run)
    button.pack()

    root2.mainloop()

Then, in Main.py:然后,在 Main.py 中:

import tkinter as tk
from tkinter import ttk
from tkinter.constants import W
from tkinter import messagebox as mb
from Script1 import script1Function         #importing Script1's function


# Execute the other python script
def openScript1():    
    root.withdraw()                         #hide this root window
    script1Function(root)                   #pass root window as parameter, so that Script1 can show root again
    

""" Open a window to select which separate script to run"""

root = tk.Tk()
root.title('Selection Window')
root.geometry('300x200')

frame_1 = tk.LabelFrame(root, text='Choose Program')
frame_1.pack()

# Using this function to update on radio button select
def radio_button_get():
    global program_int
    choice = radio_ID.get()
    if(choice == 1):
        program_int = 1
    elif(choice == 2):
        program_int = 2

# Display confirmation popup
def run_script():
    global program_int                      #you forgot to make it global
    if(program_int == 1):
        select = mb.askokcancel("Confirm", "Run choice 1?")
        if(select == 1):
            openScript1()
        else:
            return
    if(program_int == 2):
        select = mb.askokcancel("Confirm", "No selection")
        if(select == 1):
            root.destroy()
        else:
            return

# Create radio buttons to select program 
radio_ID = tk.IntVar()
radio_ID.set(2)
program_int = 2     # Set default selection

choice_1 = tk.Radiobutton(frame_1, text='Execute Script 1', variable=radio_ID, value=1, command=radio_button_get)
choice_1.pack()
no_choice = tk.Radiobutton(frame_1, text='No Selection', variable=radio_ID, value=2, command=radio_button_get)
no_choice.pack()

# Button to run the selected code
run_button = ttk.Button(root, text='Run', command=run_script)
run_button.pack()
root.mainloop()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Pyinstaller将运行bash脚本的python脚本转换为可执行文件 - Convert python script which runs a bash script to executable file with Pyinstaller 使用sc.exe创建作为Windows服务运行的Python脚本 - Creating a Python script that runs as a Windows service using sc.exe 如何使用 pyinstaller 从 python 脚本制作 a.exe? - How to make a .exe from python script with pyinstaller? 如何使用pyinstaller将chromedriver.exe与在selenium webdriver上运行的python脚本合并? - How to Merge chromedriver.exe with a python script that runs on selenium webdriver using pyinstaller? Python 使用 pyinstaller 创建 EXE 后将图像转换为视频的脚本出现问题 - Problem with Python Script that converts images to video after creating EXE with pyinstaller 如何从使用 cvxpy 和 CBC 的 python 脚本中使用 pyinstaller 构建 exe? - How to build exe with pyinstaller from python script which uses cvxpy and CBC? 使用pyinstaller使其执行后,python脚本不起作用 - python script not working after using pyinstaller to make it .exe 使用 PyInstaller 将 python 3.7 脚本转换为 exe 时出错:ModuleNotFoundError - Error while converting python 3.7 script to exe using PyInstaller: ModuleNotFoundError 如何从已经转换为exe的python脚本运行pyinstaller? - How to run pyinstaller from python script already converted to exe? Python - 执行 .exe 时 pyinstaller 脚本不起作用 - Python - pyinstaller script not working when executing the .exe
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM