I've been working on a download manager that automatically opens a GUI menu whenever a new file is downloaded, allowing me to specify a save location. Currently, I use the following Python script to detect new downloads and trigger the menu: from watchdog.observers import Observer import time from globals import DOWNLOADS_FOLDER import os import threading import menu from collections import deque TEMP_FILE_EXTENSIONS = {'.tmp', '.crdownload', '.download', '.part', '.swp', '.temp'} class DownloadHandler(FileSystemEventHandler): def __init__(self): """Initialize the handler.""" self.open_threads = True self.events_to_handle = deque() self.menu_thread_lock = threading.Lock() self.menu_thread = threading.Thread(target=self.loop_through_menus, daemon=True) self.menu_thread.start() def on_created(self, event: FileSystemEvent): """Handle file created events.""" file_path = event.src_path self.events_to_handle.append(file_path) def on_moved(self, event: FileSystemEvent): """Handle file moved events.""" original_path = event.src_path file_path = event.dest_path if self.is_download_folder(original_path) and file_path.endswith(tuple(TEMP_FILE_EXTENSIONS)): self.events_to_handle.append(file_path) def loop_through_menus(self): """Loop through events and handle them.""" while self.open_threads: if self.events_to_handle: with self.menu_thread_lock: # Ensure thread safety when modifying the deque file_path = self.events_to_handle.popleft() self.new_download_file(file_path) else: time.sleep(0.1) def new_download_file(self, file_path): """Check if the file is in Downloads and move it if not temporary.""" if self.is_download_folder(file_path): if not file_path.endswith(tuple(TEMP_FILE_EXTENSIONS)) and not os.path.basename(file_path).startswith("."): print(file_path) self.create_and_run_menu(file_path) def create_and_run_menu(self, file_path): """Create and run the file move menu.""" menu.run(file_path) def is_download_folder(self, file_path): """Check if the file is in the Downloads folder.""" return os.path.dirname(file_path) == DOWNLOADS_FOLDER def close_thread(self): """Gracefully stop the background thread.""" self.open_threads = False self.menu_thread.join() if __name__ == "__main__": event_handler = DownloadHandler() observer = Observer() # Set observer to monitor the Downloads folder (use absolute path if needed) observer.schedule(event_handler, DOWNLOADS_FOLDER, recursive=True) observer.start() try: while True: time.sleep(1) finally: observer.stop() observer.join() event_handler.close_thread() However, I've encountered an issue: Most Python GUI frameworks don't work well with threads. I've tried both PyQt6 and Tkinter, but neither worked. Instead, I get the following error: libc++abi: terminating due to uncaught exception of type NSException Since threading seems to be an issue, I’m looking for alternative solutions: Are there any lightweight GUI frameworks that handle this better? Any way to handle my current implementation without using threading? Continue reading...