Search code examples
pythonpython-3.xpython-multithreadingpyautoguipynput

Tcl_AsyncDelete with pynput and pyautogui


In a simplified version of the code:

from pynput import keyboard
import time
import pyautogui


class Test:
    def __init__(self):
        self.paused = False

    def on_activate(self):
        if self.paused:
            pyautogui.alert(text='was paused', title='title', button='button')
            self.paused = False
        elif self.paused is False:
            pyautogui.alert(text='was not paused', title='title', button='button')
            self.paused = True


test = Test()
pyautogui.alert(text='test', title='title', button='button')
hotkey = keyboard.GlobalHotKeys({
    '<ctrl>+a': test.on_activate
})
hotkey.start()

while True:
    time.sleep(1)

I will get the error Tcl_AsyncDelete: async handler deleted by the wrong thread.

Now I understand that this comes from issues handling threading, or rather the lack of said handling. I noticed that if the code runs without the alert() below the class declaration; there is never any such error.

I believe I understand that this comes from pynput working on another thread than the first pyautogui call was made; however since I no longer have a use for for alert boxes there is there a way to "properly close" it in that thread and operate it on the other?

I am at a slight loss and any input or help would be greatly appreciated.


Solution

  • I've managed to find a workaround solution it seems. The 'solution' as it stands it to simply not use pyautogui for those prompts and to build a unique tkinter box per call for those listener calls. My resulting end code is:

    from pynput import keyboard
    import time
    import pyautogui
    import tkinter as tk
    import tkinter.messagebox as messagebox
    
    
    def send_alert(text, title):
        root = tk.Tk()
        root.withdraw()
        messagebox.showinfo(title, text)
        root.destroy()
    
    
    class Test:
        def __init__(self):
            self.paused = False
    
        def on_activate(self):
            if self.paused:
                send_alert('paused', 'title')
                self.paused = False
            elif self.paused is False:
                send_alert('not paused', 'title')
                self.paused = True
    
    
    test = Test()
    pyautogui.alert(text='test', title='title', button='button')
    
    hotkey = keyboard.GlobalHotKeys({
        '<ctrl>+a': test.on_activate
    })
    hotkey.start()
    
    while True:
        time.sleep(1)