How to compile Tkinter as an executable for MacOS?

Question:

I’m trying to compile a Tkinter app as an executable for MacOs. I tried to use py2app and pyinstaller. I almost succeed using py2app, but it returns the following error:

Traceback

The Info.plist file must have a PyRuntimeLocations array containing string values for preferred Python runtime locations.  
These strings should be "otool -L" style mach ids; "@executable_stub" and "~" prefixes will be translated accordingly.

This is how the setup.py looks like:

from setuptools import setup

APP = ['main.py']
DATA_FILES = ['config.json']
OPTIONS = {
    'argv_emulation': True
}

setup(
    app=APP,
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

And this is the directory structure:

-modules/---__init.py__
|        | 
|        -- gui_module.py
|        |
|        -- scraper_module.py
|        |
|        -- app.ico
|
-config.json
|
-countries_list.txt
|
-main.py
|
-requirements.txt
|
-setup.py

I’m happy to share more details and the files if you need them.

Asked By: Y4RD13

||

Answers:

The problem was that you need to give an executable path for the python framework you have on your MacOs. So I modify the setup.py

setup.py

from setuptools import setup

class CONFIG:
    VERSION = 'v1.0.1'
    platform = 'darwin-x86_64'
    executable_stub = '/opt/homebrew/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib' # this is important, check where is your Python framework and get the `dylib`
    APP_NAME = f'your_app_{VERSION}_{platform}'
    APP = ['main.py']
    DATA_FILES = [
        'config.json', 
        'countries_list.txt', 
        ('modules', ['modules/app.ico']),
        # this modules are automatically added if you use __init__.py in your folder
        # ('modules', ['modules/scraper_module.py']),
        # ('modules', ['modules/gui_module.py']),
    ]

    OPTIONS = {
        'argv_emulation': False,
        'iconfile': 'modules/app.ico',
        'plist': {
            'CFBundleName': APP_NAME,
            'CFBundleDisplayName': APP_NAME,
            'CFBundleGetInfoString': APP_NAME,
            'CFBundleVersion': VERSION,
            'CFBundleShortVersionString': VERSION,
            'PyRuntimeLocations': [
                executable_stub,
                # also the executable can look like this:
                #'@executable_path/../Frameworks/libpython3.4m.dylib',
            ]
        }
    }

def main():
    setup(
        name=CONFIG.APP_NAME,
        app=CONFIG.APP,
        data_files=CONFIG.DATA_FILES,
        options={'py2app': CONFIG.OPTIONS},
        setup_requires=['py2app'],
        maintainer='foo bar',
        author_email='[email protected]',
    )

if __name__ == '__main__':
    main()

Then you need to run python3 setup.py py2app and now you can go and just double click on your_app_{VERSION}_{platform}.app.

Recomendations by the py2app docs:

  1. Make sure not to use the -A flag
  2. Do not use --argv-emulation when the program uses a GUI toolkit (as Tkinter) py2app options docs
Answered By: Y4RD13

I have the same issue but I don’t have .dylib for Python, I’m using PyCharm…What can I do?

Answered By: HNT