Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.app made using PyInstaller closes straight away?

I have attempted to convert my python program into a .app using PyInstaller. The actual code runs fine through IDLE, but everytime I try and run the newly converted .app, it closes straight away. Below is my .spec file and my .py file. I have edited the .spec file, adding in the text file I import in my .py file.

PYTHON FILE:

#CENTRALCOAST: 2250-2420
#CENTRALCOAST2: 2250-2267
#NORTHERNBEACHES: 2084-2108
CentralCoast = []
NorthernBeaches = []
OOR = []
Invalid = []
import math
def numLen(num):
  return len(str(abs(num)))

with open('postcodes.txt') as input_file:
    long_list = [line.strip() for line in input_file]
    for i in range(len(long_list)):
        long_list[i] = int(long_list[i])
for each in long_list:
    if 2084 <= each <= 2108: #NorthernBeaches
        NorthernBeaches.extend([each])
for each in long_list:
    if 2250 <= each <= 2267: #CentralCoast
        CentralCoast.extend([each])
for each in long_list:
    if not 2250 <= each <= 2267:
        OOR.extend([each])
#for each in long_list:
#    if numLen(each) != 4:
#        Invalid.extend([each])

Total = len(CentralCoast) + len(OOR) + len(NorthernBeaches) + len(Invalid)

print("Central Coast:", len(CentralCoast), "------", round(len(CentralCoast)/Total,2), "%")
print("")
print("Northern Beaches:", len(NorthernBeaches), "------", round(len(NorthernBeaches)/Total,4), "%")
print("")
print("Out of Range:", len(OOR), "------", round(len(OOR)/Total,2), "%")
print("")
#i = 0
#for i in OOR:
#  print(i)
#  i = i + 1
print("Invalid Entry:", len(Invalid), "------", round(len(Invalid)/Total,4), "%")
print("")
print("")
print("Total:", Total)
exit = input("")

SPEC FILE:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['algorithmPOSTCODE.py'],
             pathex=['/Users/CooperTimewell'],
             binaries=[],
             datas=[('postcodes.txt', '.')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='algorithmPOSTCODE',
          debug=False,
          strip=False,
          upx=True,
          console=False )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='algorithmPOSTCODE')
app = BUNDLE(coll,
             name='algorithmPOSTCODE.app',
             icon=None,
             bundle_identifier=None)

How do I stop it from closing straight away? Thankyou.

like image 597
CoopDaddio Avatar asked Feb 05 '18 07:02

CoopDaddio


People also ask

What are the options of pyinstaller?

pyinstaller "C:\Documents and Settings\project\myscript.spec" A full list of the pyinstaller command’s options are as follows: Name of scriptfiles to be processed or exactly one .spec file. If a .spec file is specified, most options are unnecessary and are ignored. Show program version info and exit.

How do I distribute my pyinstaller app on multiple platforms?

If you need to distribute your application for more than one OS, for example both Windows and macOS, you must install PyInstaller on each platform and bundle your app separately on each. You can do this from a single machine using virtualization.

How do I get the version of an object in pyinstaller?

Or you can apply the unicode () function to the object to reproduce the version text file. Under macOS, PyInstaller always builds a UNIX executable in dist . If you specify --onedir, the output is a folder named myscript containing supporting files and an executable named myscript .

How do I get the dependency graph from pyinstaller?

If you specify --log-level=DEBUG to the pyinstaller command, PyInstaller additionally generates a GraphViz input file representing the dependency graph. The file is build/name/graph-name.dot in the work-path= directory. You can process it with any GraphViz command, e.g. dot , to produce a graphical display of the import dependencies.


Video Answer


5 Answers

After many hours scouring/tinkering, I think I have found a solution!!

I have been having the same issue. This is defined by a Pyinstaller build that works fine on Windows and Linux, but closes immediately after building on Mac. Like you, the Mac build app closes after opening, but if you navigate through the app folder and open the Unix Executable directly it runs flawlessly. Your spec file looks perfect to me.

For me I traced the issue down to my program having to write files to the disk, whether it be creating a log file, or creating a shelf file (which I use for save date). When you run a pyinstaller build Macs will do all their run-time things in a random temp folder. For some reason Macs can find their way to the correct run-time temp folder when run from the unix executable, but get lost when run from the app. You COULD use _meipass to guide your log/shelf file (or whatever) to the correct temp folder, but this causes other problems. Some newer macs don't have permission to write there, and additionally you get a new temp folder every time you open the program, making it useless for logs or saves.

To resolve this issue use the following snippet:

import sys
import os
if getattr(sys, 'frozen', False):
    Current_Path = os.path.dirname(sys.executable)
else:
    Current_Path = str(os.path.dirname(__file__))

And then connect it to your log/shelf/save file names accordingly:

shelfFile = shelve.open(os.path.join(Current_Path, 'example_data'))

This solution will make any created file drop right next to your Unix Executable in the Mac app bundle, and NOT in the random temp file. Macs will find the location properly, and you will be able to reference the same file every time you open the program. My program also now opens from double clicking the app as intended.

I've been coming back and trying to solve this problem for MONTHS. Hopefully someone else finds this useful.

like image 122
Ancalabro Avatar answered Oct 21 '22 11:10

Ancalabro


I had the same problem as you even though I knew my code wasn't supposed to close immediately since it waited for user_input. When I ran my code from the terminal using python my_script.py the program would run fine.

Here is how I fixed it:

I reinstalled pyinstaller using:

pip install pyinstaller

I think that this was my main thing because the first time I installed it, I believe my antivirus prevented some of the components from installing correctly and when I reinstalled it, it probably patched in the holes.

I also tried a different command-line command. I explicitly stated for the final .exe to open a console and keep it open using the -c flag. Note: On Windows, this option will have no effect if the first script is a ‘.pyw’ file. It looked like this:

pyinstaller -c -F -i cm_icon.ico console_monopoly.py 

the -F flag was to bundle everything into one .exe instead of having a lot of files surrounding my .exe in the dist/ folder.

the -i flag is for adding an icon to my program.

Hope this helps!

like image 37
JoshuaMHew Avatar answered Oct 21 '22 10:10

JoshuaMHew


Maybe try to launch the executable from the windows >execute >cmd windows instead of double clicking on the executable (I suppose you are using windows)

UPDATE

This method will show it clearly if there is any error causing your application to closes prematurely

like image 22
Matt Dnv Avatar answered Oct 21 '22 12:10

Matt Dnv


In your case, because you set the console flag to False in your .spec file, the console window will not be displayed, preventing the output of your program from being displayed. Change this flag to True.

It is also possible that the application may be closing because it is unable to import a package or find an external file, which prevents your application from launching. To view the error messages associated with running your executable, run the .app (or .exe) file from the terminal (or command prompt): /path/to/app/dist/MyApp.app/Contents/MacOS/MyApp for Mac (in Terminal), /path/to/app/dist/MyApp.exe for Windows (in Command Prompt). This will allow you to observe any errors that may exist after the app was bundled. If the program does fail during an import statement, you may need to add a package to the hiddenimports list in the .spec file.

like image 2
apogalacticon Avatar answered Oct 21 '22 10:10

apogalacticon


The simplest way that I could work around this issue is by adding a input at the end of the code before the code execution completes.

input("Press enter to proceed...")

None of the answers I found could provide a similar functionality

Additionally how this helped me is, if the user hits enter directly, I made it so that the current instance is closed and a new instance of the app pops up right away. This is helpful if the user had accidentally input a wrong value for a previous input.
And if the user enters any other value, the process stops without creating a new instance.

like image 2
Gangula Avatar answered Oct 21 '22 10:10

Gangula