python / cpython

The Python programming language
https://www.python.org
Other
62.15k stars 29.86k forks source link

Tkinter - Can't find a usable init.tcl #111754

Open oldium opened 10 months ago

oldium commented 10 months ago

Bug report

Bug description:

I tried to add widgetPlus from Tklib and its dependency snit from Tcllib to my project, but executing root.tk.call("package", "require", "widgetPlus") after instantiating root = tkinter.Tk() failed with Tcl error:

_tkinter.TclError: Can't find a usable init.tcl in the following directories:
    C:/Users/oldium/AppData/Local/Programs/Python/Python312/lib/tcl8.6 C:/Users/oldium/AppData/Local/Programs/Python/lib/tcl8.6 C:/Users/oldium/AppData/Local/Programs/lib/tcl8.6 C:/Users/oldium/AppData/Local/Programs/Python/library C:/Users/oldium/AppData/Local/Programs/library C:/Users/oldium/AppData/Local/Programs/tcl8.6.13/library C:/Users/oldium/AppData/Local/tcl8.6.13/library

Strangely, the same application worked when started as exe after PyInstaller was used. I tracked the problem down to the minimal test case (as used by Tcllib module snit):

import glob
import os
import sys
import tkinter as tk
from pathlib import Path

if __name__ == "__main__":
    tcl = tk.Tcl()
    interpreter = tcl.call("interp", "create")
    tcl.call("interp", "delete", interpreter)
    tcl.call("puts", "It worked!")

I also found a workaround (I used glob to prevent fixing on a particular Tcl/Tk version), which works both in “normal” and venv environments:

# Fix Tcl/Tk folder
os.environ["TCL_LIBRARY"] = str(Path(glob.glob(os.path.join(sys.base_prefix, "tcl", "tcl*", "init.tcl"))[0]).parent)
os.environ["TK_LIBRARY"] = str(Path(glob.glob(os.path.join(sys.base_prefix, "tcl", "tk*", "pkgIndex.tcl"))[0]).parent)
os.environ["TIX_LIBRARY"] = str(Path(glob.glob(os.path.join(sys.base_prefix, "tcl", "tix*", "pkgIndex.tcl"))[0]).parent)

It looks like the Tcl/Tk installation works fine but needs additional configuration on the Python side. And please note that the workaround is usable for the Python's Tcl/Tk installation and does not consider existing Tcl/Tk installations and existing *_LIBRARY environmental variables.

CPython versions tested on:

3.11, 3.12

Operating systems tested on:

Windows

oldium commented 10 months ago

This works in PyInstaller's generated exe because it sets the TCL_LIBRARY and TK_LIBRARY by itself as seen in Process Explorer:

image

Maybe Python could do the same as PyInstaller does, i.e. set TCL_LIBRARY and TK_LIBRARY (and TIX_LIBRARY?) if they are not already set?