Closed devmgardner closed 2 years ago
That's because tkinter
isn't a distribution. If you can't pip install
it then --collect-all
won't work for it. This boils down to the same issue as #6458 - collect_all()
assumes that its argument names both a package and a distribution so it falls if a package is named differently to the distribution it was installed from or, in your case, if the package is part of the standard library.
Why are you adding --hidden-import=tkinter --collect-all=tkinter
anyway? What happens if you leave it out?
The issue remains the same, but without --hidden-import=tkinter
, I get no error message. It was a suggestion given in a SO thread about a similar issue.
That's because
tkinter
isn't a distribution. If you can'tpip install
it then--collect-all
won't work for it. This boils down to the same issue as #6458 -collect_all()
assumes that its argument names both a package and a distribution so it falls if a package is named differently to the distribution it was installed from or, in your case, if the package is part of the standard library.
I'm not quite sure why this was closed, as it's not a duplicate. I still have the same issue without the --hidden-import=tkinter
and --collect-all=tkinter
statements, I just don't get a warning message during packaging.
Maybe try packaging with console enabled first, so you can see error messages during runtime? I imagine your buttons "do nothing" because the callbacks trigger exceptions and in no-console mode, you have no way of seeing those (unless they also bring whole application down, but that's not necessary the case with callbacks).
Other than that, you'll have to provide a minimum reproducer - without seeing what your code does, our guess about what's going on is as good as yours (except the fact that message about tkinter missing is a red herring, and is result of using --collect-all
against a package that has no dist metadata).
Packaged with console enabled, I get an error about a free variable being referenced before assignment on one of the buttons, but that's it for console output. The button that's assigned quit() does nothing and produces no console output, and there's no onselect() console output either to tell me why the tkinter canvas isn't updating.
I'll have to figure something out for a minimum reproducer; I was intending to push this program to production over the weekend but haven't been able to compile for Windows or macOS and actually get it functioning, and my Linux machine is down right now due to display manager issues.
@devmgardner can you post the traceback?
Exception in Tkinter callback
Traceback (most recent call last):
File "tk_main.py", line 58, in ini_check
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Workstation2\\Desktop\\vsc\\tk_main\\binaries\\windows\\pyinstaller_test\\dist\\tk_main\\tk_main.ini'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "tkinter\__init__.py", line 1921, in __call__
File "tk_main.py", line 348, in <lambda>
NameError: free variable 'button1_func' referenced before assignment in enclosing scope
What's the tk_main.ini
file for?
It's a file meant to house the license key as well as some other important info for the program; it's basically just a deterrent to dissuade anyone from trying to distribute the program as their own. It gets generated on first run, and is checked at each subsequent run. I'm not sure why the ini_check() function is in the stack trace as it's only called at the end of the tk_main.py file.
if __name__ == '__main__':
ini_check()
Are all the paths you use in your app relative or absolute? If they aren't relative then make them relative to __file__
.
I only ever use relative paths; I have the three lines below set as a snippet for my Python development.
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
I use os.path.join(currentdir, 'filename.ext')
for everything.
I do have an update, however minor it may be. With a completely fresh install of Python 3.10.4 from Python.org/downloads instead of through anaconda, I'm able to reproduce the same exact issues on MacOS now as I've had on Windows. So that tells me I'll at least be able to provide cross-platform support for my application once these issues are resolved.
I'd recommend switching to using pathlib
where possible, but that's up to you :P.
Do you get the same issue when you build in onedir mode? It's generally best to get it working with onedirectory first, then convert it to onefile.
Unfortunately yes, I do still get the same issue with onedir mode. IIRC, the last time I built it with with onefile it didn't work at all.
Fantastic news! I went through and restructured a significant chunk of my code in my TopLevel, and it mostly works now! For whatever reason, a lot of the problems seemed to be related to functions being called before they were technically defined, and I've restructured it in a good order to get everything defined before it's called; it was quite the puzzle considering what references what and where/how, but I was able to manage it. My only remaining problem is in --onefile mode, the program does not seem to generate the .log file or the .ini file. Below is an excerpt from my ini_gen() function to show how it's being written. Any suggestions? Btw, it does work properly in --onedir mode, just not --onefile mode. Ideally I'd like to get it working in --onefile mode so I can more easily package it for MacOS as well.
def ini_gen(license_key):
fhand = open(os.path.join(currentdir, 'tk_main.ini'), 'w')
timestamp = round(time.time(),2)
fhand.write(f'{timestamp}\n')
fhand.write(f'{license_key}\n')
hasher = hashlib.md5()
if platform.system() == 'Windows':
with open(os.path.join(currentdir, 'tk_main.exe'), 'rb') as khand:
buf = khand.read()
hasher.update(buf)
My only remaining problem is in --onefile mode, the program does not seem to generate the .log file or the .ini file.
fhand = open(os.path.join(currentdir, 'tk_main.ini'), 'w')
(and from earlier comment:)
currentdir = os.path.dirname(os.path.realpath(__file__))
If currentdir
is based on __file__
, then in onefile mode, this ends up pointing into temporary directory where the onefile program is extracted. So your ini and log files are likely written there, and then removed once the program exists.
I'd like to get it working in --onefile mode so I can more easily package it for MacOS as well.
Why would onefile be easier for macOS? Assuming you want to generate app bundle, you're more likely to run into issues with code signing and notarization that you won't be able to solve via post-processing...
And from more general perspective, if this is meant to be serious application, you should avoid writing files into application bundle at runtime:
C:\Program Files
)So it might be better to store the persistent run-time-generated files into appropriate OS-specific user-settings directory.
I've since updated it to write the .log and .ini files into the user's home directory, which will only pose a problem if the user changes/updates their HOME $PATH variable frequently, which I don't foresee being an issue considering the target audience of the program.
The final issue I'm having is a segmentation fault 11 with the MacOS version of the program. A lot of the issues I've run into stemmed from either the way I wrote functions, the paths I used, or the order in which my functions were executing. The program is ready to deploy for both Windows and Linux, but this segmentation fault 11 on running the compiled app on MacOS is posing a problem.
I can get the licensing screen to appear and go through with the API call properly, but as soon as it tries to load my main window it exits with the seg fault.
EDIT: My logger gave me the following output AFTER generating the tk_main.ini file in the exact directory in which it said it couldn't find it.
2022-04-22 13:28:18,160 - tk_main - ERROR
[Errno 2] No such file or directory: '/Users/devingardner/tk_main.ini'
2022-04-22 13:28:18,161 - tk_main - ERROR
Traceback (most recent call last):
File "tk_main.py", line 59, in ini_check
FileNotFoundError: [Errno 2] No such file or directory: '/Users/devingardner/tk_main.ini'
Y'know, come to think of it. I don't think the seg fault is coming from ini_check(). Because ini_check() determines it's not able to find the file, then calls the licensing screen. The licensing screen is then (after successful license activation) supposed to call the main window. I'm getting the seg fault after successful activation, so somewhere between the activation and the main window coming up, I'm having an issue that's not being logged.
Random other problem, --onefile is now not making a .app file or using my icon, but I believe that has something to do with my use of --uac-admin.
--uac-admin
is ignored on MacOS.
Interesting, then I'm not sure why it's suddenly just making a Unix exec instead of a .app file.
Are you sure using --uac-admin
makes a difference to the output?
A .app
is made by --windowed
mode.
That's odd, as for most of my compiling time these last few days it was making a .app
with just --onefile
. I imported faulthandler
to see where the seg fault was occurring, and this is the best I got. Seems it's having trouble with tkinter maybe?
Current thread 0x000000010fbef600 (most recent call first):
File "tkinter/commondialog.py", line 45 in show
File "tkinter/filedialog.py", line 384 in askopenfilename
File "tk_main.py", line 740 in choose_file
File "tk_main.py", line 327 in choose
File "tk_main.py", line 731 in __init__
File "tk_main.py", line 773 in main
File "tk_main.py", line 207 in submit_license
File "tk_main.py", line 264 in <lambda>
File "tkinter/__init__.py", line 1921 in __call__
File "tkinter/__init__.py", line 1458 in mainloop
File "tk_main.py", line 274 in license_screen
File "tk_main.py", line 74 in ini_check
File "tk_main.py", line 777 in <module>
Extension modules: PIL._imaging, PIL._imagingft (total: 2)
Segmentation fault: 11
logout
I also got this in the error report.
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x000000000000001c
Exception Codes: 0x0000000000000001, 0x000000000000001c
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace SIGNAL, Code 11 Segmentation fault: 11
Terminating Process: exc handler [56253]
I have resolved every issue except for the segmentation fault. It really doesn't impede the usage of the application; it merely requires the user to reopen the app after licensing. However, I don't necessarily want to deploy with an existing seg fault in the app and force MacOS users to have to reopen the app after licensing. I could most likely (using pyinstaller --onedir
and Platypus) refactor my code and skip around this seg fault, but that would take another half day (that I don't have today) of work at the least.
It seems I'm not the only one getting this seg fault issue with tkinter and pyinstaller, but I've yet to find a fix that works. Any help would be greatly appreciated.
Can you reproduce the segfault with a minimal stand-alone example (e.g., a window and button that opens that filedialog)? If you can, then please provide a reproducer (along with macOS version and python version you are using). Otherwise, you're pretty much on your own...
Below is my minimum reproducer. I've removed some things for security of course, and was able to reproduce the same segmentation fault at the same time using one of my testing license keys.
import tkinter as tk, requests as rq, platform, os, sys, time, hashlib, logging, traceback, Vigenere_Helper, zipfile, re, subprocess
import tkinter.ttk as ttk
from tkinter.constants import *
from tkinter import PhotoImage, messagebox
from logging.handlers import RotatingFileHandler
#
import faulthandler
faulthandler.enable()
#
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
homedir = os.path.expanduser(f'~{os.getlogin()}')
#
logger = logging.getLogger("tk_main")
logger.setLevel(logging.DEBUG)
handler = RotatingFileHandler(os.path.join(homedir, 'tk_main.log'), maxBytes=100000, backupCount=5)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s\n%(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
#
def get_device_uuid():
if platform.system() == "Linux":
# linux
try:
return subprocess.run('cat /etc/machine-id', shell=True).stdout
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
elif platform.system() == "Darwin":
# OS X
cmd = """ioreg -ad2 -c IOPlatformExpertDevice |
xmllint --xpath '//key[.="IOPlatformUUID"]/following-sibling::*[1]/text()' -
"""
try:
return subprocess.run(cmd, shell=True).stdout
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
elif platform.system() == "Windows":
try:
from wmi import WMI
return WMI().Win32_ComputerSystemProduct()[0].UUID
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
#
def ini_gen(license_key):
with open(os.path.join(homedir, 'tk_main.ini'), 'w') as fhand:
timestamp = round(time.time(),2)
fhand.write(f'{timestamp}\n')
fhand.write(f'{license_key}\n')
hasher = hashlib.md5()
if platform.system() == 'Windows':
with open(os.path.join(homedir, 'Documents', 'tk_main', 'tk_main.exe'), 'rb') as khand:
buf = khand.read()
hasher.update(buf)
elif platform.system() == 'Darwin':
with open(os.path.join(homedir, 'Documents', 'tk_main', 'tk_main.app'), 'rb') as khand:
buf = khand.read()
hasher.update(buf)
elif platform.system() == 'Linux':
with open(os.path.join(homedir, 'Documents', 'tk_main', 'tk_main'), 'rb') as khand:
buf = khand.read()
hasher.update(buf)
fhand.write(f'{hasher.hexdigest()}\n')
package = {}
package['type'], package['datetime'], package['license_key'], package['hash'], package['UUID'] = 'ini_gen', timestamp, license_key, hasher.hexdigest(), get_device_uuid()
try:
rq.post('http://myworkingapi.com', json=package, allow_redirects=False)
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
fhand.close()
#
def license_screen(parent_window):
lic_win = tk.Toplevel(parent_window)
lic_win.geometry("450x300+413+395")
lic_win.minsize(72, 15)
lic_win.maxsize(900, 600)
lic_win.resizable(1, 1)
lic_win.title("tk_main Licenser")
lic_win.configure(background="#d9d9d9")
def submit_license(license_input):
cipher = "Removed for security"
try:
license_sub = rq.post('http://myworkingapi.com',json={'type':'license_submit', 'license_key':license_input}, allow_redirects=False)
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
if "Removed":
try:
ini_gen(license_input)
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
time.sleep(5)
try:
lic_win.destroy()
parent_window.destroy()
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
try:
main()
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
elif "Removed":
try:
messagebox.showerror('Licensing Error','This license has already been activated. Please reach out to support at support@devinmgardner.com for any questions or concerns.')
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
elif "Removed":
try:
messagebox.showerror('Licensing Error','The key you entered is invalid. Please double check for any mistakes, and reach out to support at support@devinmgardner.com with any questions or concerns.')
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
elif "Removed":
try:
messagebox.showerror('Licensing Error','The key you entered has previously been disabled, and a new key generated. Please reach out to support at support@devinmgardner.com with any questions or concerns.')
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
#
Label1 = tk.Label(lic_win)
Label1.place(relx=0.267, rely=0.167, height=22, width=189)
Label1.configure(background="#d9d9d9")
Label1.configure(foreground="#000000")
Label1.configure(text='''Enter your license key below''')
#
entrybox1 = tk.Entry(lic_win)
entrybox1.place(relx=0.044, rely=0.467, height=25, relwidth=0.182)
entrybox1.configure(background="white")
entrybox1.configure(font="TkFixedFont")
entrybox1.configure(foreground="#000000")
entrybox1.configure(insertbackground="black")
#
entrybox2 = tk.Entry(lic_win)
entrybox2.place(relx=0.289, rely=0.467, height=25, relwidth=0.182)
entrybox2.configure(background="white")
entrybox2.configure(font="TkFixedFont")
entrybox2.configure(foreground="#000000")
entrybox2.configure(insertbackground="black")
#
entrybox3 = tk.Entry(lic_win)
entrybox3.place(relx=0.533, rely=0.467, height=25, relwidth=0.182)
entrybox3.configure(background="white")
entrybox3.configure(font="TkFixedFont")
entrybox3.configure(foreground="#000000")
entrybox3.configure(insertbackground="black")
#
entrybox4 = tk.Entry(lic_win)
entrybox4.place(relx=0.778, rely=0.467, height=25, relwidth=0.182)
entrybox4.configure(background="white")
entrybox4.configure(font="TkFixedFont")
entrybox4.configure(foreground="#000000")
entrybox4.configure(insertbackground="black")
#
submit_button = tk.Button(lic_win, command = lambda: submit_license(f'{entrybox1.get()}-{entrybox2.get()}-{entrybox3.get()}-{entrybox4.get()}'))
submit_button.place(relx=0.422, rely=0.7, height=28, width=79)
submit_button.configure(activebackground="#ececec")
submit_button.configure(activeforeground="#000000")
submit_button.configure(background="#d9d9d9")
submit_button.configure(cursor="fleur")
submit_button.configure(foreground="#000000")
submit_button.configure(highlightbackground="#d9d9d9")
submit_button.configure(highlightcolor="black")
submit_button.configure(text='''Submit''')
lic_win.mainloop()
class Toplevel1:
def __init__(self, top=None):
'''This class configures and populates the toplevel window.
top is the toplevel containing window.'''
_bgcolor = '#d9d9d9' # X11 color: 'gray85'
_fgcolor = '#000000' # X11 color: 'black'
_compcolor = '#d9d9d9' # X11 color: 'gray85'
_ana1color = '#d9d9d9' # X11 color: 'gray85'
_ana2color = '#ececec' # Closest X11 color: 'gray92'
#
top.geometry("600x600+195+172")
top.minsize(1, 1)
top.maxsize(3840, 2160)
top.resizable(1, 1)
top.title("tk_main")
#
self.top = top
#
self.Labelframe1 = tk.LabelFrame(self.top)
self.Labelframe1.place(relx=0.067, rely=0.050, relheight=0.700
, relwidth=0.867)
self.Labelframe1.configure(relief='groove')
self.Labelframe1.configure(text='''Label''')
#
self.outputFrame = tk.LabelFrame(self.top)
self.outputFrame.place(relx=0.067, rely=0.750, relheight=0.200
, relwidth=0.867)
#
self.scrollbar = tk.Scrollbar(self.outputFrame)
self.scrollbar.pack(side = 'right',fill='y')
self.outputwindow = tk.Text(self.outputFrame, yscrollcommand = self.scrollbar.set,wrap = "word",width = 200,font = "{Arial} 15")
self.outputwindow.pack(side = 'left',fill='y')
self.scrollbar.config(command = self.outputwindow.yview)
self.outputwindow.yview('end')
self.outputwindow.config(yscrollcommand=self.scrollbar.set)
self.outputwindow.insert('end','Error messages will appear here.\n')
self.outputwindow.config(state='disabled')
self.outputwindow.see('end')
#
self.new_List = tk.Listbox(self.Labelframe1)
self.new_List.place(relx=0.038, rely=0.109, relheight=0.750
, relwidth=0.450, bordermode='ignore')
self.new_List.configure(background="white")
self.new_List.configure(font="TkFixedFont")
self.new_List.configure(selectmode='multiple')
#
def choose():
listsize = self.new_List.size()
self.new_List.delete(0,listsize-1)
activelist = []
global location
location = choose_file()
global displaylist
displaylist = []
displaylist = list_new_files(location)
global displaydict
displaydict = {}
try:
for locat,val in enumerate(displaylist):
newval = re.search('\/([^\/]*\..*)',val).group(1)
displaydict[newval] = val
self.new_List.insert(locat, newval)
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
#
self.new_Canvas = tk.Label(self.Labelframe1)
self.new_Canvas.place(relx=0.538, rely=0.109, relheight=0.750
, relwidth=0.450, bordermode='ignore')
self.new_Canvas.configure(text='Font examples will appear here.')
#
self.browseButton = tk.Button(self.Labelframe1)
self.browseButton.place(relx=0.3653846, rely=0.875, height=33, width=140, anchor='nw')
self.browseButton.configure(borderwidth="2")
self.browseButton.configure(compound='left')
self.browseButton.configure(text='''Choose a different ZIP file''')
self.browseButton.configure(command=choose)
#
def endprog():
sys.exit()
#
self.exitButton = tk.Button(self.Labelframe1)
self.exitButton.place(relx=0.6826923, rely=0.875, height=33, width=140, anchor='nw')
self.exitButton.configure(borderwidth="2")
self.exitButton.configure(compound='left')
self.exitButton.configure(text='''Exit''')
self.exitButton.configure(command=endprog)
#
choose()
#
def choose_file():
from tkinter import Tk, filedialog
root = Tk()
root.withdraw()
root.attributes('-topmost', True)
try:
open_file = filedialog.askopenfilename()
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
global filelist
try:
filelist = zipfile.ZipFile(open_file,mode='r')
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
try:
data = filelist.namelist()
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
try:
return data
except Exception as e:
logger.error(str(e))
logger.error(traceback.format_exc())
#
def list_new_files(openfile):
files = [a for a in openfile if '.ttf' in a]
return files
def main(*args):
'''Main entry point for the application.'''
global root
root = tk.Tk()
root.protocol( 'WM_DELETE_WINDOW' , root.destroy)
# Creates a toplevel widget.
global _top1, _w1
_top1 = root
_w1 = Toplevel1(_top1)
root.mainloop()
if __name__ == '__main__':
license_window = tk.Tk()
license_window.withdraw()
license_screen(license_window)
EDIT: This was built using pyinstaller --onedir --windowed --exclude-module=PyQt5 --exclude-module=matplotlib --key=MyKeyHere minimum_reproducer.py
and I was only able to open it using the unix executable in the folder it created, not through the .app file. I'm still having issues with the Tcl/Tk install on MacOS as well.
Python: Python 3.10.4
PyInstaller: pyinstaller==5.0 pyinstaller-hooks-contrib==2022.4
MacOS: macOS Monterey Version 12.2.1
This code (after removing non-existent Vigenere_Helper
from imports) segfaults on my test system without pyinstaller
being involved at all:
$ python program.py
Fatal Python error: Segmentation fault
Current thread 0x00000001112f3600 (most recent call first):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/tkinter/commondialog.py", line 45 in show
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/tkinter/filedialog.py", line 384 in askopenfilename
File "/Users/rok/Development/pyi-tkinter/program.py", line 272 in choose_file
File "/Users/rok/Development/pyi-tkinter/program.py", line 225 in choose
File "/Users/rok/Development/pyi-tkinter/program.py", line 262 in __init__
File "/Users/rok/Development/pyi-tkinter/program.py", line 305 in main
File "/Users/rok/Development/pyi-tkinter/program.py", line 105 in submit_license
File "/Users/rok/Development/pyi-tkinter/program.py", line 162 in <lambda>
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/tkinter/__init__.py", line 1921 in __call__
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/tkinter/__init__.py", line 1458 in mainloop
File "/Users/rok/Development/pyi-tkinter/program.py", line 172 in license_screen
File "/Users/rok/Development/pyi-tkinter/program.py", line 311 in <module>
Segmentation fault: 11
So this is not our problem...
That's interesting, because my test program worked perfectly fine when run from the .py file. I really do not understand what the issue is here.
Well, tkinter
is not exactly my field of expertise, but is seems to me you are destroying your first tkinter.Tk
instance (the license_window
, later called parent_window
inside license_screen()
) within the submit_button callback that is being executed in that Tk instance's context - I don't imagine that's legal? You should probably destroy it after lic_win.mainloop()
exits...
I'm about to be away from my office for a few hours, so I will have to give that a try tonight. I didn't realize I had the order wrong in those, good looking out!
Looking into @rokm's comment more, I found where I destroy the window. lic_win.mainloop()
exits in the first line shown below, and then the parent_window
is destroyed immediately after. This is how tkinter closes the mainloop()
.
lic_win.destroy()
parent_window.destroy()
I'm considering creating a SO post for this under tkinter specifically, because it appears seg fault 11 isn't uncommon with Tkinter windows. I'll do some more digging tonight and update this thread if I find anything of use.
Try placing print statements around lic_win.mainloop()
, and you'll see that this main loop does not exit at that point; and you create instantiate new Tk.Tk in the main()
call following those destroy lines, in the same callback that's still running in the context of the first Tk.Tk instance.
Like I said, I'm not tkinter
expert, but that looks fishy to me, and you'll have hard time convincing me that this segfault is a pyinstaller problem.
I really don't understand how this is a problem. It wasn't a problem during testing, it hasn't been a problem at all until now. I just checked again just to see, and you're right. I got a segmentation fault where one did not exist before. I made it all the way through development and testing without a single seg fault at these lines, and by all accounts it should be destroying the lic_win
and THEN destroying the parent_window
, but something's not going right. I'll have to make a SO post about it.
Description of the issue
When packaging a complex program written with Tkinter, most functionality is gone. I have finally been able to package the application and get it to actually open, however: my filedialog() does not appear at startup as it's supposed to, my listbox onselect() function does not update my canvas view as it's supposed to, and two of my three buttons do nothing. None of these issues are present when running the base .py file from command line. I do receive warnings during packaging that tkinter was not found, which is baffling considering it's now included with Python.
Context information (for bug reports)
pyinstaller --version
:5.0
A minimal example program which shows the error
My main.py file is 38KB and this being a closed-source project, would take me days to get to a point where I could post it here.
Stacktrace / full error message
EDIT: This is the command I use to package the file:
pyinstaller --onedir --noconsole --key=ThisIsAKey --hidden-import=tkinter --collect-all=tkinter main.py