Pyinstaller: Bundled MacOS App opens and closes immediately

Created on 22 Oct 2018  Ā·  42Comments  Ā·  Source: pyinstaller/pyinstaller

Problem:

An app created with the $ pyinstaller --onefile --windowed myapp.spec command creates an app bundle that opens and closes immediately: both when it is doubles clicked and run using $ open ./myapp.app.

The output to the console.app is:
Oct 22 12:33:13 Teghans-MacBook-Pro com.apple.xpc.launchd[1] (test.10192[42509]): Service exited with abnormal code: 255. Running pyinstaller with the .spec EXE(..., debug=1, ...) does not generate additional debugging messages in the console.app.

The unix executable ./dist/myapp runs fine. The unix executable in the app bundle ./dist/myapp.app/Contents/MacOs/myapp also runs fine. This issue is simply with clicking or attempting to open the ./dist/myapp.app app bundle.

Software:

  • Using an Anaconda virtual env with Python==3.7, pyinstaller==3.4
  • MacOS Sierra 10.12.6
  • The example program I am trying to run:
import tkinter as tk
window = tk.Tk()
window.title("Welcome to LikeGeeks app")
lbl = tk.Label(window, text="Hello")
lbl.grid(column=0, row=0)

window.geometry('350x200')
window.mainloop()

NOTE: that this problem also persisted for me using a non-tkinter python script: therefore I find it likely that using tkinter is not in anyway related. However, I would like to be able to create an app using tkinter GUI, thus, my interest in resolving this issue with respect to this python script.

Important Info for Related Issues:

This issue has been referenced in several other threads but has been conflated with other issues. Issue #1804 addresses this exact issue, however, that thread has been conflated with users who are having their app crash because of loading files within their python script. #604 also addresses this issue and has been closed because, again, some users commented on that issue and discussed how their problem was with the paths of loading a file within the python script. #1454 also addresses this issue and again does not provide solutions. The issue of app crashing due to file loading within the python script can be solved by consulting those threads.

The distinction between this issue and the issue of file loading within the python script can be diagnosed by the following (as I understand it):

The file loading issue is diagnosed by:

  • App closes immediately when double-clicked in finder.
  • App opens when running $ open ./myapp.app in terminal and crashes when it encounters a line in the python script to load a certain file

This issue is diagnosed by:

  • App opens and closes immediately when double-clicked in finder.
  • App opens and closes immediately when running $ open ./myapp.app in terminal.
  • The unix executable in the app runs fine when run using $ open ./myapp.app/Contents/MacOs/myapp
  • The output to the console.app is the highly uninformative Oct 22 12:33:13 Teghans-MacBook-Pro com.apple.xpc.launchd[1] (test.10192[42509]): Service exited with abnormal code: 255.

This issue is about why the unix executable generated by the --onefile option works perfectly, yet the mac app bundle will open and immediately close.

Most helpful comment

I think I found the problem and the solution

The same thing was happening to me, I had python 3.7.3 installed through the installer downloaded from python.org, this Python comes with its own tcl which is version 8.6.8, also had pyinstaller 3.4 and my bundled App opens and close immediately as @tnightengale described in his post, then I installed python through Homebrew, it install version 3.7.3, but the difference is that it uses the tcl 8.5.9 version. Doing this my bundled App launch and doesn't close, however how it was an older version of tcl, many of the things I had in my GUI did not work or work badly. then researching more thoroughly to discover what was happening I found a way to make everything work with Python that downloads from Python.org the one that brings tcl version 8.6.8.

Problem:
tcl version that comes with the python.org python installation

Solution:
what you have to do is very simple once we have our bundled App we must enter to its content to the tcl folder.

myApp.app -> Contents -> Resources -> tcl

once we are there we have to modify the init.tcl file on line 19 where it says:

package require -exact Tcl 8.6.8

We must replace it with:

package require -exact Tcl 8.5.9

Once this is done, our application will open normally with a double click.

I hope this also works for you.

All 42 comments

I encountered the exact same problem (both double clicking on the app, and running open myapp.app from the command line does not work whereas calling directly the executable inside the app from the command line works).

One way to make the double clicking works is to make an app bundle manually a bit oddly. After running the pyinstaller --onefile myapp.py that creates an executable dist/myapp, I created the following bash script called run_other:

#!/bin/bash
DIR=$(cd "$(dirname "$0")"; pwd)
open $DIR/myapp

and then run the following commands to make it as an app bundle:

mkdir -p run_other.app/Contents/MacOS
cp run_other dist/myapp run_other.app/Contents/MacOS/
chmod +x run_other.app/Contents/MacOS/run_other

This setting will work, even if it is not very delicate and beautiful.

I join here an error.log I obtained as a crash report when launching the app using my computer running under the beta MacOS if that can help some people to understand where this comes from.

_P.S: I am running the tests under MacOS Mojave, using the Python3.7 distributed from python.org, and both PyInstaller3.4 and the current development version (I used essentially the same code simply adding a close button)._

If you can run your app from command line with $ open myapp then this is not that issue. In my post ./myapp simply refers to the full unknown path to your app bundle. Please read the Important Info for Related Issues: section of my original post. There is already so much conflated misinformation about this issue on various threads. I spent 3hrs reading every pertinent post on GitHub and StackExchange to try and untangle and differentiate the two types of issues. Please do not hijack this thread by bringing related but not identical issues to focus. Thank you.

I conscientiously read all your thread before commenting, and this is definitely the same issue. I will modify my previous comment so that it is clearer to you what I made to make it work (the open myapp means the same as your open ./myapp.app/Contents/MacOs/myapp only that the path from which it is called is different and not open myapp.app which is indeed not working).

it is so weird but @AmbroiseGrau 's solution worked fine for me :suspect:

just a thing to remember, in the appname.app, the appname should match the binary in Contents/MacOS folder and reference in the run_other bash file

ps: MacOS High Sierra 10.13.6 (17G3025)

The workaround seems to keep a terminal open while the application is open. Is there any way around this?

Hi,
I have exactly this problem even with your simple program, on Mac OS Sierra 10.12.6, PyInstaller 3.4 with PR #3830, and python 3.7.3. I've tried to have a look - even with the debug version and loggin various errors in console - but I have found nothing more.
Then I've tried to look inside, and I've taken various traces with dtruss. I'm attaching them, hoping that someone could discover what's wrong ;-)

Cheers,
Nico

working -> dtruss.cmd.txt
not working, trace by name -> dtruss.app_name.txt
not working, trace by PID -> dtruss.app.txt
not working, clicking the app icon -> dtruss.app_click.txt

I have the same problem.
Using pyinstaller with the .spec EXE(..., debug=1, ...)
In the console app, under system.log
I get

LOADER: Running tk_main.py
Failed to execute script tk_main
LOADER: OK.

...

LOADER: returning child exit status 255
Service exited with abnormal code: 255

This only happens if in my script I import tkinter and instantiate a root

import tkinter as tk
root = tk.Tk()

I found a workaround to the problem
I use platypus to build a bundle around the bundle created by Pyinstaller.
Specifically I put MyApp.app (created by Pyinstaller) in the Bundled Files of Platypus.
Then, In Platypus I use a bash script such as this:

#!/bin/bash
./MyApp.app/Contents/MacOS/MyApp

In platypus, make sure to select "Run in background" so that you don't have two icons appearing.
Hope this helps

EDIT
In alternative a simpler solution is to put the Unix executable (instead of the whole app) inside the Bundled Files of Platypus.
And in the bash simply put:

#!/bin/bash
./MyApp

This would result in the executable to run with a default icon in the Dock. You can fix this by adding the following lines in your python script:

root = tk.Tk()
logo_fname = resource_path(os.path.join('assets','logo.png'))
img = tk.Image("photo", file=logo_fname)
root.iconphoto(True, img) 

assuming that you have defined

def resource_path(relative_path):
     if hasattr(sys, '_MEIPASS'):
         return os.path.join(sys._MEIPASS, relative_path)
     return os.path.join(os.path.abspath("."), relative_path)

You should make sure that the logo.png is in the asset folder.

I have encountered the same problem. Running a minimal program print("Hello World!") and pyinstaller Hello.py -windowedyields the same issue; runs when running the binary directly, doesn't when running it by clicking. I am aware that the minimal program should open a console.

In the Mac system log I see these kind of issues when running the program, that may be related;

LSExceptions shared instance invalidated for timeout.

lsd
Writing store (no GC) 0x7fa4f050fdb0 with writer 0x7000077502e0

lsd
Non-fatal error enumerating at <private>, continuing: Error Domain=NSCocoaErrorDomain Code=260 "The file ā€œPlugInsā€ couldn’t be opened because there is no such file." UserInfo={NSURL=PlugIns/ -- file:///Users/--/workspace/Hello/dist/Hello.app/Contents/, NSFilePath=/Users/--/workspace/Hello/dist/Hello.app/Contents/PlugIns, NSUnderlyingError=0x7f8082445180 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

libsqlite3.dylib
cannot open file at line 42263 of [95fbac39ba]

libsqlite3.dylib
os_unix.c:42263: (2) open(/var/db/DetachedSignatures) - No such file or directory

libsqlite3.dylib
Failed to register <private> trusted: NSOSStatusErrorDomain/-67060

I found another project with a similar issue where the theory was an issue with Mac sandboxing. https://github.com/groue/GRDB.swift/issues/450

I am not sure if it's related or not, but worth mentioning.

Version info:
Python 3.7.3
macOS Mojave 10.14.4
Pyinstaller, development version 3.5.dev0+d74052489

Hi,
I've tested the helloworld simple program with previous PyInstaller version & python 2.7.16.

print('Hello world')
raw_input('Press ENTER to continue ....')

Unfortunately, the resulting bundled app is not working even on Pyinstaller 2.0 of 2015 - which is the first that supported 64 bit ;-(

So, I'm wondering if the bundled apps have never worked on modern MacOs...

Nico

I think I found the problem and the solution

The same thing was happening to me, I had python 3.7.3 installed through the installer downloaded from python.org, this Python comes with its own tcl which is version 8.6.8, also had pyinstaller 3.4 and my bundled App opens and close immediately as @tnightengale described in his post, then I installed python through Homebrew, it install version 3.7.3, but the difference is that it uses the tcl 8.5.9 version. Doing this my bundled App launch and doesn't close, however how it was an older version of tcl, many of the things I had in my GUI did not work or work badly. then researching more thoroughly to discover what was happening I found a way to make everything work with Python that downloads from Python.org the one that brings tcl version 8.6.8.

Problem:
tcl version that comes with the python.org python installation

Solution:
what you have to do is very simple once we have our bundled App we must enter to its content to the tcl folder.

myApp.app -> Contents -> Resources -> tcl

once we are there we have to modify the init.tcl file on line 19 where it says:

package require -exact Tcl 8.6.8

We must replace it with:

package require -exact Tcl 8.5.9

Once this is done, our application will open normally with a double click.

I hope this also works for you.

Hi Manuel,
thanks for sharing your findings.

I have found that this trick resolves the problem in some situations. But, at least with my program, the resulting app is still not working on a clean system (without any additional python).
Anyway, indeed your work seems to point to the right direction!

It worked for me Manuel! Very nice! I tried a bunch of other options, but yours finally solved the problem. It seems like the new tcl/tk integration with Python by default, rather than simply installing it as a module, is causing a lot of problems for everyone.

The only additional thing I had to do from Manuel's suggestion was remove the -F (--onefile) option from the command. For some reason, the -F option would not generate the proper files in the resource folder. The final command I used was:

pyinstaller -w -n name_of_app python_file.py, and then replaced package require -exact Tcl 8.6.8 with package require -exact Tcl 8.5.9.

I had another issue earlier with tk, which I resolved using AmbroiseGrau's answer at this link. I hope that helps out!

Pepperpo's solution worked well for me - THANKS!!, and is the simplest one. Quick comments:
1) When bundling a 3.6 + Tkinter application using Pyinstaller on Mac, I ran into the problem discussed above.
2) Platypus bundled it well and quickly, but if you send the app to someone, it requires the same Python interpreter (i.e. the one used to build the app) to be installed on their Mac.
3) By bundling the app with Pyinstaller, and then bundling the bundle with Platypus, you get an executable that can be run on other people's Mac's without any Python interpreter installed there.

For me, this works:
1. Reorder the analysis scripts list so that the main script is first (doing this on Windows breaks the app though; Linux seems to not care either way).
2. Copy /Library/Frameworks/Python.framework/Versions/3.7/lib/{tcl,tk}* to TheApp.app/Contents/lib.

EXCELLENT jamsilva!

It worked like a charm for me! I didn't need point 1, I've just made a lib folder inside TheApp.app/Contents and copied /Library/Frameworks/Python.framework/Versions/3.7/lib/{tcl,tk}* inside it. The resulting App works fine from the GUI an it also works where python 3 is not installed at all ;-)
With a bit more work, I've then found that you only need a single file:

/Library/Frameworks/Python.framework/Versions/3.7/lib/tcl8/8.5/msgcat-1.6.1.tm

to be copied in the (new) folder:

TheApp.app/Contents/lib/tcl8/8.5/

This file is related to localization stuff and it makes sense in this scenario...
So, even if not so elegant, for me the problem is totally resolved with this simple workaround.

Thanks a lot jamsilva!

That's awesome, @nicozanf. I was too lazy to narrow it down further to just a single file as you did :stuck_out_tongue: .
But it's nice to see that it is working for someone else. Hopefully this information will lead to a fix.

Edit: For the Tkinter application I'm testing I need the file mentioned by @nicozanf (tcl8/8.5/msgcat-1.6.1.tm) + the tcl8.6 folder + the tk8.6 folder and placing the main script first in the list as explained before.

I confirm that the "single file workaround" works fine for me, on python 3.7.4 and 2.7.16.
And also the APP obtained works fine on a clean MacOs system (without any updated python installed).

Cheers,
Nico

I've struggled with this problem for a while and found two things necessary to correct it in my case (tkinter app, Python 3.7.1, PyInstaller 3.5, MacOS 10.13.6).

1) Edit hook-_tkinter.py to ensure tcl/tk libraries are copied into the bundle correctly, as described by @AmbroiseGrau in thread #3753

2) Copy msgcat-1.6.1.tm into TheApp.app/Contents/lib/tcl8/8.5/ as described by @nicozanf above. I am using tcl/tk version 8.6 and this still works if you rename TheApp.app/Contents/lib/tcl8/8.5/ as 8.6 instead, so the presence of this file seems to be the important point. But note that msgcat-1.6.1.tm can only be found in /Library/Frameworks/Python.framework/Versions/3.7/lib/tcl8/8.5, not in the tcl8.6 equivalent.

i.e.

$ cd /Library/Frameworks/Python.framework/Versions/3.7/lib
$ find . -name "*msgcat*"
  ./tcl8/8.5/msgcat-1.6.1.tm

Many thanks for suggestions in this thread

Do not update to MacOS 10.14.6

Guys if you are in a MacOS version before 10.14.6 please do not update, the new version of MacOS has a bug with tkinter applications and they stop working, at the time these applications are executed the system freezes and returns to the login screen, here is a link with more information about it. https://discussions.apple.com/thread/250549297

I have written a script that automates @manuelf23 suggestion regarding changing the init.tcl file to a lower version of tcl.

fork or clone

  • cd location/of/app.py
  • git clone https://github.com/jacob-brown/TCLChanger.git
  • pyinstaller --windowed app.py
  • python TCLChanger/TCLChanger.py

Place it in the same directory as the app.py script and run after the pyintsaller build.
N.B. as @therealFIGBERT mentioned don't use --onefile when building.

The bases of the script is as follows.

import os

    for folderName, subfolders, filenames in os.walk('dist'):
        if '.app' in folderName: 
            for filename in filenames:
                if filename == 'init.tcl':
                    fileTCL = str(folderName + '/' + filename)

    with open(fileTCL,'r') as f:
        dfAll=f.readlines()

    with open(fileTCL,'w') as f:
        for line in dfAll:
            if 'package require -exact Tcl' in line:                              
                f.writelines("package require -exact Tcl 3.5.9\n") # rollback to 3.5.9 rather than 3.6 
            else:
                f.writelines(line)

I think I found the problem and the solution

The same thing was happening to me, I had python 3.7.3 installed through the installer downloaded from python.org, this Python comes with its own tcl which is version 8.6.8, also had pyinstaller 3.4 and my bundled App opens and close immediately as @tnightengale described in his post, then I installed python through Homebrew, it install version 3.7.3, but the difference is that it uses the tcl 8.5.9 version. Doing this my bundled App launch and doesn't close, however how it was an older version of tcl, many of the things I had in my GUI did not work or work badly. then researching more thoroughly to discover what was happening I found a way to make everything work with Python that downloads from Python.org the one that brings tcl version 8.6.8.

Problem:
tcl version that comes with the python.org python installation

Solution:
what you have to do is very simple once we have our bundled App we must enter to its content to the tcl folder.

myApp.app -> Contents -> Resources -> tcl

once we are there we have to modify the init.tcl file on line 19 where it says:

package require -exact Tcl 8.6.8

We must replace it with:

package require -exact Tcl 8.5.9

Once this is done, our application will open normally with a double click.

I hope this also works for you.

There is no such file in my case in Resources but only icon-windowed.icns.
Here is my simple testing script and I issued here.

def simple_test():
    input('Wait a second...')
if __name__ == '__main__':
    simple_test()

Is your solution specific to @tnightengale .py code?

import tkinter as tk
window = tk.Tk()
window.title("Welcome to LikeGeeks app")
lbl = tk.Label(window, text="Hello")
lbl.grid(column=0, row=0)

window.geometry('350x200')
window.mainloop()

I encountered the exact same problem (both double clicking on the app, and running open myapp.app from the command line does not work whereas calling directly the executable inside the app from the command line works).

One way to make the double clicking works is to make an app bundle manually a bit oddly. After running the pyinstaller --onefile myapp.py that creates an executable dist/myapp, I created the following bash script called run_other:

#!/bin/bash
DIR=$(cd "$(dirname "$0")"; pwd)
open $DIR/myapp

and then run the following commands to make it as an app bundle:

mkdir -p run_other.app/Contents/MacOS
cp run_other dist/myapp run_other.app/Contents/MacOS/
chmod +x run_other.app/Contents/MacOS/run_other

This setting will work, even if it is not very delicate and beautiful.

I join here an error.log I obtained as a crash report when launching the app using my computer running under the beta MacOS if that can help some people to understand where this comes from.

_P.S: I am running the tests under MacOS Mojave, using the Python3.7 distributed from python.org, and both PyInstaller3.4 and the current development version (I used essentially the same code simply adding a close button)._

This make-do method works for my case.

But it actually does NOT address the original app problem.
and I think this issue has nothing to do with tcl-tk or tkinter GUI base my case.

This method successfully addressed tkinter error for macOS user and here are my notes with Catalina 10.15.1+Python 3.7.5+tcl-tk 8.6.9.

I encountered the exact same problem (both double clicking on the app, and running open myapp.app from the command line does not work whereas calling directly the executable inside the app from the command line works).

One way to make the double clicking works is to make an app bundle manually a bit oddly. After running the pyinstaller --onefile myapp.py that creates an executable dist/myapp, I created the following bash script called run_other:

#!/bin/bash
DIR=$(cd "$(dirname "$0")"; pwd)
open $DIR/myapp

and then run the following commands to make it as an app bundle:

mkdir -p run_other.app/Contents/MacOS
cp run_other dist/myapp run_other.app/Contents/MacOS/
chmod +x run_other.app/Contents/MacOS/run_other

This setting will work, even if it is not very delicate and beautiful.

I join here an error.log I obtained as a crash report when launching the app using my computer running under the beta MacOS if that can help some people to understand where this comes from.

_P.S: I am running the tests under MacOS Mojave, using the Python3.7 distributed from python.org, and both PyInstaller3.4 and the current development version (I used essentially the same code simply adding a close button)._

Thank you for the solution! While this works, it there a way to not show the Terminal when the app is launched in Finder?
I have a PyQt5 app, it solves the double click issue but meanwhile opens up another Terminal for run_other script.

I had the same issue and was able to fix it by going Application>Resources>MacOs and pasting Tcl and Tk folders from Frameworks library (System>Library>System frameworks).
Note: When you paste them they should be in folders named Tk and Tcl and include Unix executable and resources folders.

That solved the problem for launching Application as well as Unix executable.

I hope this saves somebody time.

MacOS Catalina 10.15.4
pyenv 1.2.18
pyinstaller 3.6
Platypus 5.3

Worth mentioning, remember that your pyinstaller build is compatible to your OS. This may be important for many python bundles because if you are going to run the unix executable in the .app remember that prior to Catalina python3 binary wasn't included in the os. This just felt worth mentioning for anybody who overlooks that detail on pyinstaller bundles, see pyinstaller docs for more details on compatibility.

Assuming that isn't your issue, in dist you have yourapp.app and then yourapp.

_When you double click the app it doesn't open. Maybe it flashes the icon in the bottom then closes instantly. When you double click the unix executable it runs the app while keeping the terminal open._

If it doesn't open for either, skip to the bottom of this post for a possible avenue to go down.

Right-click and hit show package contents. We are going to use this executable.

Contents/MacOS/yourapp

First, make mental note we are only using platypus to create a tiny app that opens that executable. We don't use just platypus without pyinstaller because platypus does not bundle python environments so it will only open if the system meets the apps requirements. I think there is a way to make that work but it sounds hacky and according to the platypus site they are hoping to include that feature soon.

Now, assuming your environment and path is setup correct; run
pyinstaller --add-data '{dependancy}.py:{anotherone}.py' --onefile --windowed 'yourapp.app'

This created what we mentioned earlier. Now, create a new file, you can throw it in your new dist , doesn't matter really, call it run_me.sh and open it using a text editor or your ide. Include this and replace "yourapp" with the correct app name.

#!/bin/bash
./yourapp.app/Contents/MacOS/yourapp

Save and close. Open platypus.

First for script path click select script and find the sh file we just made; select it.
After selecting the file, rename the app in the platypus window "App Name" entry.
Change interface to none. Make sure to select run in background and Remain running after execution.
Finally hit the + in the bottom half of the window for bundled files then locate and include yourapp.app that was located in your dist folder. Hit create app, choose a directory and bundle.
You should now be able to double click the icon and it should open.

If it doesn't, or if you are not getting it to open even when you double click the executable, and you are using pyenv and homebrew, make sure that your python build is seeing your homebrew installs, especially tcl-tk if you are using tkinter. I have found a lot of open issues on missing tkinter. Really, if you are using homebrew, pyenv, and pyinstaller together, it is vital you make sure your pyenv installs can see homebrew packages you need. You can set this for specific packages in your pyenv build process by pyenv uninstall {your v} and then doing something like this...

env \                                                                                       
  PATH="$(brew --prefix tcl-tk)/bin:brew --prefix sqlite)/bin:$PATH" \
  LDFLAGS="-L$(brew --prefix tcl-tk)/lib: -L$(brew --prefix sqlite)/lib" \
  CPPFLAGS="-I$(brew --prefix tcl-tk)/include:-I$(brew --prefix sqlite)/include" \
  PKG_CONFIG_PATH="$(brew --prefix tcl-tk)/lib/pkgconfig:$(brew --prefix sqlite)/lib/pkgconfig" \
  CFLAGS="-I$(brew --prefix tcl-tk)/include:-I$(brew --prefix sqlite)/include" \
  PYTHON_CONFIGURE_OPTS="--enable-shared --with-tcltk-includes='-I$(brew --prefix tcl-tk)/include' --with-sqlite-includes='-I$(brew --prefix sqlite)/include' --with-tcltk-libs='-L$(brew --prefix tcl-tk)/lib -ltcl8.6 -ltk8.6' --with-sqlite-libs='-L$(brew --prefix sqlite)/lib' " \
  pyenv install {your version}

I've included two dependancies in that build example, tcl-tk and sqlite, so you can see what multiple packages would look like if you don't know already.

I hope something in this either helps or sparks the thing that helps.

I think I found the problem and the solution

The same thing was happening to me, I had python 3.7.3 installed through the installer downloaded from python.org, this Python comes with its own tcl which is version 8.6.8, also had pyinstaller 3.4 and my bundled App opens and close immediately as @tnightengale described in his post, then I installed python through Homebrew, it install version 3.7.3, but the difference is that it uses the tcl 8.5.9 version. Doing this my bundled App launch and doesn't close, however how it was an older version of tcl, many of the things I had in my GUI did not work or work badly. then researching more thoroughly to discover what was happening I found a way to make everything work with Python that downloads from Python.org the one that brings tcl version 8.6.8.

Problem:
tcl version that comes with the python.org python installation

Solution:
what you have to do is very simple once we have our bundled App we must enter to its content to the tcl folder.

myApp.app -> Contents -> Resources -> tcl

once we are there we have to modify the init.tcl file on line 19 where it says:

package require -exact Tcl 8.6.8

We must replace it with:

package require -exact Tcl 8.5.9

Once this is done, our application will open normally with a double click.

I hope this also works for you.

Thanks so much for this solution. I had been struggling with this issue for last 2 days, but this solved my problem.

I found a solution to this issue that does not require copying msgcat-1.6.1.tm or any other files to the application bundle:

  1. Find console.tcl in /Library/Frameworks on the machine you make the build. Usually this is located in either of these locations:
/Library/Frameworks/Python.framework/Versions/Current/lib/tk8.6/console.tcl
/Library/Frameworks/Tk.framework/Versions/8.6/Resources/Scripts/console.tcl
  1. Replace msgcat::mc in the file with ::tk::msgcat::mc

Alternatively here's a command that does it for you:

sudo sed -i .bak "s#\[msgcat::mc#\[::tk::msgcat::mc#g" /Library/Frameworks/Python.framework/Versions/Current/lib/tk8.6/console.tcl

Finally, here's a diff for the file:

--- /Library/Frameworks/Python.framework/Versions/3.7/lib/tk8.6/console.tcl 2020-07-24 21:07:12.000000000 +0200
+++ /Library/Frameworks/Python.framework/Versions/3.7/lib/tk8.6/console.tcl 2020-07-24 21:08:15.000000000 +0200
@@ -740,9 +740,9 @@
 }
 proc ::tk::console::FontchooserVisibility {index} {
     if {[tk fontchooser configure -visible]} {
-   .menubar.edit entryconfigure $index -label [msgcat::mc "Hide Fonts"]
+   .menubar.edit entryconfigure $index -label [::tk::msgcat::mc "Hide Fonts"]
     } else {
-   .menubar.edit entryconfigure $index -label [msgcat::mc "Show Fonts"]
+   .menubar.edit entryconfigure $index -label [::tk::msgcat::mc "Show Fonts"]
     }
 }
 proc ::tk::console::FontchooserFocus {w isFocusIn} {

Tk 8.5 used to include msgcat, but 8.6 no longer does - that's why msgcat-1.6.1.tm is located in the 8.5 folder and reverting to 8.5.9 works. Instead of using the msgcat package, Tk 8.6 defines fallback functions in the tk namespace. However, console.tcl wasn't using these fallback functions and failed to run without the msgcat package present.

One thing that still puzzles me is why launching the executable directly works, but opening the .app crashes. My suspicion is that the problematic function only gets called when opening app bundles.

Most of the workarounds posted here are about Tk, but this issue is not specific to that. I have the same problem with a simple Python code:

print('Hello world.')
input('Press Enter to exit.')

The binary runs okay in Terminal, but double-clicking the .app doesn't work.

But maybe this is intentional, as the docs are confusing about this:

-w, --windowed, --noconsole

Windows and Mac OS X: do not provide a console window for standard i/o. On Mac OS X this also triggers building an OS X .app bundle. On Windows this option will be set if the first script is a ā€˜.pyw’ file. This option is ignored in *NIX systems.

So the -w option is required to make a .app bundle, but this also disables the console window. So if my app does not draw its own GUI, then it would be effectively useless. Is this the intended behavior? If so, then I would like to make a feature request to let console apps work with a double-click.

I'm on Mojave 10.14.6 using Python 3.7 with pyinstaller 3.6. This is what I see in the system log when trying to open with open dist/test.app

Default     0x0                  545    0    lsd: (LaunchServices) [com.apple.launchservices:default] Non-fatal error enumerating at PlugIns/ -- file:///Users/elliott/source/cfn-demo/dist/test.app/Contents/, continuing: Error Domain=NSCocoaErrorDomain Code=260 "The file ā€œPlugInsā€ couldn’t be opened because there is no such file." UserInfo={NSURL=PlugIns/ -- file:///Users/elliott/source/cfn-demo/dist/test.app/Contents/, NSFilePath=/Users/elliott/source/cfn-demo/dist/test.app/Contents/PlugIns, NSUnderlyingError=0x7fa3e471e830 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Default     0x0                  545    0    lsd: (LaunchServices) [com.apple.launchservices:appinstallation] Parsed Info.plist for test
Default     0x0                  545    0    lsd: (LaunchServices) [com.apple.launchservices:appinstallation] Parsed MobileInstallation data for test
Error       0x0                  545    0    lsd: (LaunchServices) [com.apple.launchservices:default] Failed to register file:///Users/elliott/source/cfn-demo/dist/test.app/ trusted: NSOSStatusErrorDomain/-67060
Default     0x0                  544    0    CommCenter: (LaunchServices) 27366555: RECEIVED OUT-OF-SEQUENCE NOTIFICATION: 0 vs 3613, 256, { "ApplicationType"="Foreground", "BundleIdentifierLowerCase"="test", "CanBecomeFrontmost"=true, "CFBundleExecutablePath"="/Users/elliott/source/cfn-demo/dist/test.app/Contents/MacOS/test", "CFBundleExecutablePathDeviceID"=16777220, "CFBundleExecutablePathINode"=41910163, "CFBundleIdentifier"="test", "CFBundleName"="test", "CFBundleNameLowerCase"="test", "CFBundlePackageType"="APPL", "ChangeCount"=517, "Hidden"=false, "LSASN"=ASN:0x0-0x485485:, "LSBundlePath"="/Users/elliott/source/cfn-demo/dist/test.app", "LSBundlePathDeviceID"=16777220, "LSBundlePathINode"=41910156, "LSDisplayName"="test", "LSExecutableFormat"="LSExecutableMachOFormat", "LSLaunchDLabel"="test.92052", "LSLaunchedByLaunchServices"=true, "LSLaunchedWithLaunchD"=true, "LSLaunchEventRecordTime"=95475574714357, "LSLaunchModifiers"={ "AddPSNArgument"=true, "LSAdditionalEnvironmentVars"={  }, "LSFrontApplicationSeed"=1859, "LSLaunchAsync"=false, "LSLaunchProgress<…>

If I run open test.app in terminal, the app opens without any error/warning.
However, if I click it from the finder, it doesn't open.
I use WXPython.
I'd appreciate any suggestion.

Same issue, small Tkinter app, Catalina, Python 3.8 but using py2app instead of pyinstaller. Just posted about it on stack overflow with some links suggesting that it may not be a Tkinter issue but rather a disk access problem. The issue only appeared in my case when I added a line opening a config file in the working directory. However, it apparently happens to people running very simple barebones scripts. Otherwise the symptoms on my end are exactly the same as everyone else here described and I'm completely confused about what could be going on here. Tkinter? File access? macOS? All three?

Environment:

Python 3.8.3

PyInstaller 4.1.dev0

Mac OS Catalina 10.15

Problem:

I tried to distribute my program made with Python 3.

I use PyInstaller to make the Mac OS bundle app : MyApp.app

When I double click on /Applications/MyApp.app, the icon bounce on bottom right corner and then close itself. Nothing happens.

If I open the executable file /Applications/MyApp.app/Contents/MacOS/MyApp from terminal, it works fine. The icon pop up and open the GUI of my software.

So I open console and double click again on MyApp.app in order to identify the source of error. Here is what I found:

Non-fatal error enumerating at <private>, continuing: Error Domain=NSCocoaErrorDomain Code=260 "Impossible to open the file « PlugIns » because it doesn't exist." UserInfo={NSURL=PlugIns/ -- file:///Applications/MyApp.app/Contents/, NSFilePath=/Applications/MyApp.app/Contents/PlugIns, NSUnderlyingError=0x7fe03dd17fb0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

Obviously we are numerous to have same issue.

I tried all the solutions proposed, but none of them worked.

This issue exists since October 2018 and no-one found the perfect solution.

Is there any Python Mac OS expert able to solve this very popular problem?

I struggled with that issue for a week. In #5109 @reritom tracked it down to using Python functions to access files on macOS and suggested using NSBundle instead. The entire discussion is worth a read if you're on macOS and having trouble accessing files with your bundled scripts. It looks a lot like the issue I had.

I agree though that at some point a more explicit error message should be displayed when compiling, as it's a popular problem indeed (although not necessarily related only to file access, I believe).

I believe the original issue is finally (mostly) understood.

@Nezz nailed it back on July 24:

https://github.com/pyinstaller/pyinstaller/issues/3820#issuecomment-663697670

This is a bug in the Tk 8.6.x code. Fortunately, it is very easily patchable as described by @Nezz. Note that if you use pyenv to install/build Python or if you build Python manually, you probably used brew to install tcl-tk so the path to the Tk console.tcl file is:

/usr/local/Cellar/tcl-tk/8.6.10/lib/tk8.6/console.tcl

To make sure you patched the right file, after running pyinstaller (WITHOUT --onefile) check that the change is in:

dist/<YOUR APPNAME>.app/Contents/MacOS/tk/console.tcl

The reason that debugging this problem has been so difficult is that it is a very early uncaught exception whose stack trace gets lost in the ether. This also is the reason that the waters have been muddied by posters saying that it is not specific to tkinter. The OP (@tnightengale) was reporting this tkinter-specific problem and we should all agree that this Issue (#3820) should be limited to the problem solved (or worked around) by the patch to console.tcl.

The following Python 3 script reproduces this problem AND captures the stack trace in a temp file that is opened in your $EDITOR:

pyi_issue_3820.py:

import tempfile
import traceback
import subprocess

try:
    import tkinter
    tkinter._test()
except:
    tmp_file = tempfile.NamedTemporaryFile(delete=False)
    with open(tmp_file.name, "a") as f:
        f.write("{}\n".format(traceback.format_exc()))
    subprocess.call(("open", tmp_file.name))  # Mac-specific

If you are experiencing Issue #3820, that script should run without errors if you run it with Python 3 from the command line:

% python pyi_issue_3820.py
=> no problem

Now build it with:

% pyinstaller --windowed pyi_issue_3820.py

Now run it:

% dist/pyi_issue_3820/pyi_issue_3820
=> no problem
% dist/pyi_issue_3820.app/Contents/MacOS/pyi_issue_3820
=> no problem
% open dist/pyi_issue_3820.app/Contents/MacOS/pyi_issue_3820
=> no problem (but there's an unwanted console)
% open dist/pyi_issue_3820.app (or double-click in Finder)
=> FAILS, with the following in your $EDITOR:

Traceback (most recent call last):
  File "pyi_issue_3820.py", line 7, in <module>
  File "tkinter/__init__.py", line 4552, in _test
  File "tkinter/__init__.py", line 2261, in __init__
_tkinter.TclError: invalid command name "msgcat::mc"

For anyone experiencing similar symptoms, but not using tkinter, just replace the "try" block in the above script with your code and you too can get a meaningful stack trace.

So now what?

As far as I can tell, this problem has not been reported to the Tcl/Tk folks:
https://core.tcl-lang.org/tk/ticket

Even if it gets fixed in Tcl/Tk, this will continue to bite MacOS+tkinter+pyinstaller users for years.

Perhaps it is worth adding code to hook-_tkinter.py to perform the console.tcl patch with something like:

  • Copy the (buggy) console.tcl file to a temporary location
  • Apply the patch to the copy of console.tcl
    (patch should be idempotent)
  • Modify the tktree Tree structure to point to the patched file for
    tk/console.tcl

That would result in the patched file being used in the bundle.

  • Why does this exception occur only on MacOs?

  • Why does this exception occur only when the .app is double-clicked in Finder (or opened from shell)?

  • What is console.tcl anyway?

https://www.tcl.tk/man/tcl8.6/TkCmd/console.htm

"The console window is a replacement for a real console to allow input and output on the standard I/O channels on platforms that do not have a real console. It is implemented as a separate interpreter with the Tk toolkit loaded, and control over this interpreter is given through the console command. The behaviour of the console window is defined mainly through the contents of the console.tcl file in the Tk library. Except for TkAqua, this command is not available when Tk is loaded into a tclsh interpreter with ā€œpackage require Tkā€, as a conventional terminal is expected to be present in that case. In TkAqua, this command is only available when stdin is /dev/null (as is the case e.g. when the application embedding Tk is started from the Mac OS X Finder)."

Aqua is the MacOS UI. While this makes sense for native Tk, I can't think of how it could ever be applicable to Python running tkinter.

I downloaded the Tk source code from:
https://prdownloads.sourceforge.net/tcl/tk8.6.10-src.tar.gz

The function Tk_CreateConsoleWindow in generic/tkConsole.c is where console.tcl is invoked:

result = Tcl_EvalEx(consoleInterp, "source $tk_library/console.tcl",
    -1, TCL_EVAL_GLOBAL);

The Tk_CreateConsoleWindow function gets called by the TkpInit function in macosx/tkMacOSXInit.c:

/*
 * If we don't have a TTY and stdin is a special character file of
 * length 0, (e.g. /dev/null, which is what Finder sets when double
 * clicking Wish) then use the Tk based console interpreter.
 */

if (getenv("TK_CONSOLE") ||
    (!isatty(0) && (fstat(0, &st) ||
    (S_ISCHR(st.st_mode) && st.st_blocks == 0)))) {
    Tk_InitConsoleChannels(interp);
    Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDIN));
    Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDOUT));
    Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDERR));

    /*
     * Only show the console if we don't have a startup script and
     * tcl_interactive hasn't been set already.
     */

    if (Tcl_GetStartupScript(NULL) == NULL) {
    const char *intvar = Tcl_GetVar2(interp,
        "tcl_interactive", NULL, TCL_GLOBAL_ONLY);

    if (intvar == NULL) {
        Tcl_SetVar2(interp, "tcl_interactive", NULL, "1",
            TCL_GLOBAL_ONLY);
    }
    }
    if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) {
    return TCL_ERROR;
    }
}

I can't see any way to fool the Tk initialization into not invoking console.tcl in the .app case, so it appears that the only solution is the console.tcl patch.

Take a look at #5175 - making sure that tcl8 directory is collected along with tcl/tk data directories solves the app bundle issues for me, both with older python.org builds that use system Tcl/Tk (8.5) and with recent ones that use their own Tcl/Tk (8.6).

@csatt I have exchanged several emails with Marc Culler who works on Tcl/Tk and reported the issue to him. He applied my proposed changes and repurposed an existing ticket of mine to track it:
https://core.tcl-lang.org/tk/tinfo?name=ab5623e0c42e2cd9c075051f07296ad129eef697880e76cd633719602caa8525

This means that newer versions of Tcl/Tk should work fine, but it hasn't been released officially yet. Also keep in mind that the bundled Tcl/Tk versions are severely lagging behind on macOS and the python.org builds.

That is great that you have Marc Culler in the loop on this, @Nezz! He is obviously the authority on all things Tcl/Tk and I'd been planning on contacting him myself if no one else had. That confirms that this is a bug in console.tcl and that your change is, technically, the "correct" fix.

However, the question remains: what can/should pyinstaller do to work around this problem? If nothing is done, people will be hitting this for years.

While the #5175 pull request proposed by @rokm isn't the "correct" fix, if it works for all cases (present, past, and future), then let's go with it! Adam, have you run that by Marc to see if he can think of any problems with it?

Meanwhile, I will review the #5175 hook-_tkinter.py changes and test in my environments.

Adam, have you run that by Marc to see if he can think of any problems with it?

@csatt I can't speak for Marc, but I personally think #5175 is good to go. I'd probably just leave a note in the hook to explain why we are collecting older modules.

OK, #5175 was merged. Now that Tcl modules are collected, the Tcl/Tk environment for the pyinstaller-built program should be the same as for the original python script/program.

This should take care of the missing msgcat, so I'm closing this issue.

(As discussed above, this does not actually fix the real underlying problem - however, fixing that is beyond the scope of pyinstaller.)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pyinstaller-tickets-migration picture pyinstaller-tickets-migration  Ā·  3Comments

TobiX picture TobiX  Ā·  3Comments

shane-zhang picture shane-zhang  Ā·  3Comments

AFAgarap picture AFAgarap  Ā·  3Comments

NobugHu picture NobugHu  Ā·  3Comments