Search code examples
pythonpython-3.xtkintertclpyinstaller

Launch different tkinter version from python app compiled with pyinstaller on Windows


I have a tkinter GUI that allows me to start any kind of program:

# main_app.py
import tkinter as tk
import subprocess

root = tk.Tk()

cmd_entry = tk.Entry(width=50)
cmd_entry.pack(side='left')

def run_script():
    sp = subprocess.run(cmd_entry.get().split(), shell=True)

run_btn = tk.Button(text="Run Command", command=run_script)
run_btn.pack(side='left')

root.mainloop()

It looks like this:

enter image description here

I can start another tkinter script from this window, for instance:

# dummy_app.py
import tkinter as tk

root = tk.Tk()
root.mainloop()

It even works when starting dummy_app.py with a different version of python. For example, I can start main_app.py with Python 3.10.8 and run the following:

C:\Path\to\python3.9\python.exe dummy_app.py

However, if I compile main_app.py into an executable with pyinstaller (v5.6.2):

pyinstaller.exe .\main_app.py --onefile

Then I get the following error when trying to run C:\Path\to\python3.9\python.exe dummy_app.py from main_app.exe:

C:/Users/.../AppData/Local/Temp/_MEI76562/tcl/init.tcl: version conflict for package "Tcl": have 8.6.9, need exactly 8.6.12
version conflict for package "Tcl": have 8.6.9, need exactly 8.6.12
    while executing
"package require -exact Tcl 8.6.12"
    (file "C:/Users/.../AppData/Local/Temp/_MEI76562/tcl/init.tcl" line 19)
    invoked from within
"source C:/Users/.../AppData/Local/Temp/_MEI76562/tcl/init.tcl"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 [list source $tclfile]"


This probably means that Tcl wasn't installed properly.

python dummy_app.py works fine however.

Why does the tcl version has to be the same when starting the script from the compiled executable? Is there a way around this?


Solution

  • The pyinstaller set the TCL/Tk path into environment variable, So you can set the env argument to subprocess.

    def run_script():
        env = os.environ.copy()
        if 'TCL_LIBRARY' in env:
            del env['TCL_LIBRARY']
        if 'TK_LIBRARY' in env:
            del env['TK_LIBRARY']
        sp = subprocess.run(cmd_entry.get().split(), shell=True, env=env)