Skip to content

Commit

Permalink
hooks: tkinter: avoid collecting data from system Tcl/Tk framework on…
Browse files Browse the repository at this point in the history
… macOS

On macOS, we do not collect system libraries in general; if
tkinter uses system Tcl/Tk 8.5 framework (older 32/64-bit
python.org builds, or brew python), we do not collect its Tk and
Tcl shared library, either. Therefore, it makes little sense to
collect the data (scripts and modules) from the system framework,
either.

This commit modifies the behavior of both _tkinter stdhook
and rthook on macOS. The stdhook now treats (None, None) returned
by _find_tcl_tk() as an indicator that the system framework is
used and that data directories should not be collected. The rthook
now sets TCL_LIBRARY and TK_LIBRARY environment variables if collected
tcl and tk directories exist, but does not raise error anymore
if they do not (under assumption that they have not been collected
from the system framework).

The behavior under other OSes remains unchanged.
  • Loading branch information
rokm committed Oct 2, 2020
1 parent dda4a76 commit 585b630
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 18 deletions.
45 changes: 33 additions & 12 deletions PyInstaller/hooks/hook-_tkinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,24 +172,35 @@ def _find_tcl_tk(hook_api):
# might depend on system Tcl/Tk frameworks and these are not
# included in 'hook_api.binaries'.
bins = getImports(hook_api.__file__)
# Reformat data structure from
# set(['lib1', 'lib2', 'lib3'])
# to
# [('Tcl', '/path/to/Tcl'), ('Tk', '/path/to/Tk')]
mapping = {}
for l in bins:
mapping[os.path.basename(l)] = l
bins = [
('Tcl', mapping['Tcl']),
('Tk', mapping['Tk']),
]

if bins:
# Reformat data structure from
# set(['lib1', 'lib2', 'lib3'])
# to
# [('Tcl', '/path/to/Tcl'), ('Tk', '/path/to/Tk')]
mapping = {}
for l in bins:
mapping[os.path.basename(l)] = l
bins = [
('Tcl', mapping['Tcl']),
('Tk', mapping['Tk']),
]
else:
# Starting with macOS 11, system libraries are hidden.
# Until we adjust library discovery accordingly, bins
# will end up empty. But this implicitly indicates that
# the system framework is used, so return None, None
# to inform the caller.
return None, None

# _tkinter depends on Tcl/Tk compiled as frameworks.
path_to_tcl = bins[0][1]
# OS X system installation of Tcl/Tk.
# [/System]/Library/Frameworks/Tcl.framework/Resources/Scripts/Tcl
if 'Library/Frameworks/Tcl.framework' in path_to_tcl:
tcl_tk = _find_tcl_tk_darwin_system_frameworks(bins)
#tcl_tk = _find_tcl_tk_darwin_system_frameworks(bins)
tcl_tk = None, None # Do not gather system framework's data

# Tcl/Tk compiled as on Linux other Unixes.
# This is the case of Tcl/Tk from macports and Tck/Tk built into
# python.org OS X python distributions.
Expand Down Expand Up @@ -245,6 +256,16 @@ def _collect_tcl_tk_files(hook_api):

tcl_root, tk_root = _find_tcl_tk(hook_api)

# On macOS, we do not collect system libraries. Therefore, if system
# Tcl/Tk framework is used, it makes no sense to collect its data,
# either. In this case, _find_tcl_tk() will return None, None - either
# deliberately (we found the data paths, but ignore them) or not
# (starting with macOS 11, the data path cannot be found until shared
# library discovery is fixed).
if is_darwin and not tcl_root and not tk_root:
logger.info('Tcl/Tk not found on macOS system or system framework is used.')
return []

# TODO Shouldn't these be fatal exceptions?
if not tcl_root:
logger.error('Tcl/Tk improperly installed on this system.')
Expand Down
19 changes: 13 additions & 6 deletions PyInstaller/hooks/rthooks/pyi_rth__tkinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@
tcldir = os.path.join(sys._MEIPASS, 'tcl')
tkdir = os.path.join(sys._MEIPASS, 'tk')

if not os.path.isdir(tcldir):
# Notify "tkinter" of data directories.
# On macOS, we do not collect data directories if system Tcl/Tk
# framework is used. On other OSes, we always collect them, so their
# absence is considered an error.
is_darwin = sys.platform == 'darwin'

if os.path.isdir(tcldir):
os.environ["TCL_LIBRARY"] = tcldir
elif not is_darwin:
raise FileNotFoundError('Tcl data directory "%s" not found.' % (tcldir))
if not os.path.isdir(tkdir):
raise FileNotFoundError('Tk data directory "%s" not found.' % (tkdir))

# Notify "tkinter" of such directories.
os.environ["TCL_LIBRARY"] = tcldir
os.environ["TK_LIBRARY"] = tkdir
if os.path.isdir(tkdir):
os.environ["TK_LIBRARY"] = tkdir
elif not is_darwin:
raise FileNotFoundError('Tk data directory "%s" not found.' % (tkdir))

0 comments on commit 585b630

Please sign in to comment.