Failed to execute script for .exe file generating using pyinstaller

Hello, I recently wrote a program that crops all the images in a directory and then stacks then all together. Then I made a simple GUI for the program which allows the user to input the directories and values. The programs have been able to run fine, but when I go to convert it to a .exe file, it states that it failed to execute the script. I used the code:

pyinstaller -w -F -i "filepath.ico" program.py

The file generates, but opening the file results in the error above. Do I have to do something additional to my code because I added the extra GUI (was able to get .exe to work without the GUI). Should I put the GUI and program in the same file? Also, my program runs fine python, but when its converted to a .exe file, there is always a 10 second delay before it will appear. This happens no matter how large the program is. I think it is due to Windows Defender block at first site. But I followed all the steps to disable it to no avail.

GUI code

from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
from PIL import Image
from natsort import natsorted
import glob
import gc

import RD_program # .py file containing the program code

# --- functions ---

def inputfile(): # opens prompt to select input folder
    master.inputdirectory = filedialog.askdirectory()
    print(master.inputdirectory)


def outputfile(): # opens prompt to select save folder
    master.outputdirectory = filedialog.askdirectory()
    print(master.outputdirectory)


def run(): # function to run entire program
    try: # if user input is incorrect, instead of stopping program, will output error
        coordinates = [int(x1input.get()), int(y1input.get()), int(x2input.get()), int(y2input.get())]
        image_count = int(countinput.get())

        RD_program.process(master.inputdirectory, coordinates, image_count, master.outputdirectory)

    except Exception as ex:
        print('ex:', ex)
        messagebox.showwarning("Warning", "Wrong arguments:\n" + str(ex))


# --- main ---

master = Tk()
master.iconbitmap("One_Dimensional_Reaction_Diffusion_Program_Icon.ico")

master.inputdirectory = None # default value at start
master.outputdirectory = None # default value at start

master.title("One Dimensional Reaction Diffusion Program")
master.geometry("440x270")

header1 = Label(master, text="One Dimensional Reaction Diffusion Program\n"
                             "Created by: Alexander Tang\n")

header1.grid(sticky="N", columnspan=8)
instructions = Label(master, text="Type in the coordinates for the upper left (x1,y1) and bottom right (x2,y2) points:")
instructions.grid(sticky="W", columnspan=8)

x1 = Label(master, text="x1: ")
x1.grid(sticky="E", column=0, row=2)
x1input = Entry(master, width=5)
x1input.grid(sticky="W", column=1, row=2)

y1 = Label(master, text="y1: ")
y1.grid(sticky="E", column=2, row=2)
y1input = Entry(master, width=5)
y1input.grid(sticky="W", column=3, row=2)

x2 = Label(master, text="x2: ")
x2.grid(sticky="E", column=4, row=2)
x2input = Entry(master, width=5)
x2input.grid(sticky="W", column=5, row=2)

y2 = Label(master, text="y2: ")
y2.grid(sticky="E", column=6, row=2)
y2input = Entry(master, width=5)
y2input.grid(sticky="W", column=7, row=2, pady=12)

count = Label(master, text="How many images are being stacked? ")
count.grid(sticky="W", column=0, row=4, columnspan=4)
countinput = Entry(master, width=5)
countinput.grid(stick="W", column=5, row=4, pady=3)

step1 = Label(master, text="1. Select the file location: ")
step1.grid(sticky="W", column=0, row=6, columnspan=4)
step2 = Label(master, text="2. Select the save location: ")
step2.grid(sticky="W", column=0, row=7, columnspan=4)

btn_input = Button(master, text="Input Files", command=inputfile) # calls the function inputfile
btn_input.grid(column=5, row=6, columnspan=2, pady=6)

btn_output = Button(master, text="Output Location", command=outputfile) # calls the function outputfile
btn_output.grid(column=5, row=7, columnspan=2)

btn_run = Button(master, text="Run", font="Helvetica, 18", bg="blue", fg="white", command=run) # calls the function run
btn_run.grid(sticky="S", column=5, row=8, columnspan=2, pady=6)

mainloop()

Program code

from PIL import Image # for image processing
from natsort import natsorted # sorting files
import glob # access files
import gc # deletes unneeded files
import os # to be able to access directories


def process(directory, coordinates, image_count, outputdirectory=None): # function assigning all variables
    x1, y1, x2, y2 = coordinates

    # Generate final image first
    # Width dependent on whether image is horizontal or vertical
    if (y2 - y1) > (x2 - x1):
        width = (y2 - y1)
        height = (x2 - x1)
    else:
        width = (x2 - x1)
        height = (y2 - y1)

    # Width is constant, total_height accounts for height above and the total number of images
    total_height = (image_count * height)
    new_im = Image.new('RGB', (width, total_height)) # Create a new colored image (RGB)

    # Keep outside of loop, if not, will reset y_offset each time
    # Indicates position of where to paste cropped image
    # Counter used to show progress of program
    y_offset = 0
    counter = 0

    # Accessing all the files using the glob module
    # The function natsorted sorts values the way Windows does
    # os.path.join(directory) opens prompt to choose folder
    # Opens all the files with the variable img in folder
    for filename in natsorted(glob.glob(os.path.join(directory, "*.*"), recursive=True)):
        img = Image.open(filename)

        # Cropping function
        selected_region = (x1, y1, x2, y2) # selected region from previous user input
        cropped_region = img.crop(selected_region) # taking opened image and cropping to selected region
        if (y2 - y1) > (x2 - x1): # If cropped area is vertical, rotate into horizontal position
            rotated_image = cropped_region.rotate(90, expand=1) # Expand 1 ensures image isn't cut off while rotating
        else:
            rotated_image = cropped_region # Does nothing if image is horizontal
        img.close() # Closes the initially opened image
        gc.collect()

        new_im.paste(rotated_image, (0, y_offset)) # (x,y) indicates which direction to offset in
        y_offset += rotated_image.size[1] # y_offset (which had position 0) + the height of the image
        counter += 1
        print(counter, " out of ", image_count, "completed.") # Shows progress of program
        if counter == image_count: # Will stop program when counter reaches number of images
            break
    final_im = new_im.rotate(180, expand=1) # stacking goes from top to bottom, rotate images at the end

    if outputdirectory is None:
        outputdirectory = directory
    final_im.save(os.path.join(outputdirectory, "stacked_image.tiff"), quality=95)


def main():
    # Convert coordinate list into variables
    print("Type in the coordinates for the upper left (x1,y1) and bottom right (x2,y2) points")
    coordinates = list(map(int, input("Separate values with a space (x1 y1 x2 y2): ").strip().split()))[:4]
    image_count = int(input("How many images are being stacked? "))
    print("Generating image...")

    process(directory, coordinates, image_count)

    print("Image completed and can be found in the output folder.")
    input("Press ENTER to close program.") # prevents prompt from instantly closing


if __name__ == " __main__": # allows you to run code without GUI
    main()

Try adding the option “–onefile” to the pyinstaller command. 

Is “program.py” the GUI .py file? If so, pyinstaller should automagically identify that you are referencing “rd_program.py” and include it … if you use --onefile.

I faced same problem. Didn’t find any way to solve.

Thank you for the reply, program.py is the GUI file. Also, do I simply just add the --onefile before the icon directory


An alternative seems to be https://anthony-tuininga.github.io/cx_Freeze/

@fire-eggs that link is broken. Can you provide an alternative? Thanks

Here you go

1 Like