ronaldoussoren / py2app

py2app is a Python setuptools command which will allow you to make standalone Mac OS X application bundles and plugins from Python scripts.
Other
343 stars 36 forks source link

Tcl/Tk from Macports is incompletely bundled #202

Open ronaldoussoren opened 8 years ago

ronaldoussoren commented 8 years ago

Original report by John O'Brien (Bitbucket: neirbowj, GitHub: neirbowj).


Synopsis

After generating an app that depends on Tkinter, if I remove or upgrade the version of Tcl/Tk installed from Macports, or if I try to run the app on a system without the Macports Tcl/Tk, the app fails with the error messages shown in the attached console log excerpt.

Analysis

py2app successfully identifies and packs the two dylib files necessary to support Tcl/Tk, but does not detect that the additional directories are required. The resources option or similar might allow the developer to explicitly or programmatically in setup.py select the additional directories, but no option permits placement in one of the necessary locations in the app bundle.

Steps to reproduce

  1. Install Macports
  2. Install python27, py27-tkinter (which will pull in Tcl/TK), and py27-py2app ports
  3. Build the hello example app
  4. Uninstall py27-tkinter and the Tcl/Tk ports
  5. Open hello.app

Work-around

After building the app, copy /opt/local/lib/tcl8.6, /opt/local/lib/tcl8, and /opt/local/lib/tk8.6 into Contents/lib.

Environment

ronaldoussoren commented 7 years ago

Original comment by davedgd (Bitbucket: davedgd, GitHub: davedgd).


John, thank you for posting the work-around. I can confirm the same issue using Python 3.5 and various related py35 Macports. Fortunately your workaround resolves the issue, for which I'm grateful.

IanBurwell commented 2 years ago

Has there been any progress on this issue? I am experiencing the same problem on py2app==0.28 and python 3.7.5 in a venv, and while the workaround succeeds for me, it is not maintainable. I will note that in my situation, I have installed tcl-tk with brew, and the location I need to copy from is /usr/local/Cellar/tcl-tk/8.6.12_1/lib/tk8.6 and /usr/local/Cellar/tcl-tk/8.6.12_1/lib/tcl8.6 respectively.

For visibility, I will include that the errors I got on my app when run on a system without tcl-tk:

  File "tkinter/__init__.pyc", line 2023, in __init__
_tkinter.TclError: Can't find a usable init.tcl in the following directories: 
    /usr/local/Cellar/tcl-tk/8.6.12_1/lib/tcl8.6 /Users/ian/Desktop/dist/csv_unlog_gui.app/Contents/lib/tcl8.6 /Users/ian/Desktop/dist/csv_unlog_gui.app/lib/tcl8.6 /Users/ian/Desktop/dist/csv_unlog_gui.app/Contents/library /Users/ian/Desktop/dist/csv_unlog_gui.app/library /Users/ian/Desktop/dist/csv_unlog_gui.app/tcl8.6.12/library /Users/ian/Desktop/dist/tcl8.6.12/library
IanBurwell commented 2 years ago

I have made a workaround through my setup.py which works for my use case. I thought I would share for those facing the same issue.

from pathlib import Path

from setuptools import setup
import tkinter as tk
import shutil
import os

APP_BASE = ['csv_unlog_gui']
APP = [n+".py" for n in APP_BASE]
DATA_FILES = []
OPTIONS = {'bdist_base': "/Users/ian/Desktop/build",
           'dist_dir': "/Users/ian/Desktop/dist"}

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

root = tk.Tk()
root.overrideredirect(True)
root.withdraw()
tcl_dir = Path(root.tk.exprstring('$tcl_library'))
tk_dir = Path(root.tk.exprstring('$tk_library'))
root.destroy()

os.makedirs(f"{OPTIONS['dist_dir']}/{APP_BASE[0]}.app/Contents/lib", exist_ok=True)
print(f"Copying TK from: {tk_dir}")
shutil.copytree(tk_dir, f"{OPTIONS['dist_dir']}/{APP_BASE[0]}.app/Contents/lib/{tk_dir.parts[-1]}")
print(f"Copying TCL from: {tcl_dir}")
shutil.copytree(tcl_dir, f"{OPTIONS['dist_dir']}/{APP_BASE[0]}.app/Contents/lib/{tcl_dir.parts[-1]}")
DanielO commented 1 year ago

+1 - I have the same issue with Python 3.9 / Tcl 8.6 from MacPorts and py2app 0.28.2 (also from Macports :)