I have a student that submitted a function like this:
def infinite_windows():
window = tkinter.Tk()
infinite_windows()
I already test things inside a try-except block. My code reports the RecursionError, but then it freezes my desktop the next time it asks for user input and I have to kill Python. The following code hangs, but only when the input() call is included:
import tkinter
def infinite_windows():
window = tkinter.Tk()
infinite_windows()
try:
infinite_windows()
except Exception as e:
print("caught the exception!")
print(e)
input("hi there") #hangs here
Is there any way for me to handle this behavior and continue running Python without removing the call to input()?
I got this as a possible solution:
import tkinter
def infinite_windows():
window = tkinter.Tk()
infinite_windows()
# Store all Tk objects in an array
_all_windows = []
class _Tk(tkinter.Tk):
def __init__(self, *args, **kwargs):
_all_windows.append(self) # Add this Tk object in the array
super().__init__(*args, **kwargs)
tkinter.Tk = _Tk # Replace tkinter's Tk class with our own
try:
infinite_windows()
except Exception as e:
print("caught the exception!")
print(e)
# Loop through and destroy all `tkinter.Tk` objects
for window in _all_windows:
try:
window.destroy()
except tkinter.TclError:
# If the window wasn't fully created/already was destroyed
pass
_all_windows.clear() # Clear the array
input("? ")
Basically I overwrite tkinter.Tk
with my own class that inherits from tkinter.Tk
(doesn't cause recursion problems because my class is constructed before I replace tkinter.Tk
). In my own class, I keep track of all tkinter.Tk
objects in a global list and destroy them at the end.
This approach works (on Ubuntu with Wayland) but has a few limitations:
tkinter.Tk
objects. Nothing we can really do about that because python is reluctant to release RAM back to the OStkinter.Tk
class like this:import tkinter
def infinite_windows(window_class=tkinter.Tk):
window = window_class()
infinite_windows()
To solve that issue, you can move the code that overwrites tkinter.Tk
before the student's code (but that will raise an error if the student tries to import something from __future__
)