Spaces:
Running
Running
| """Temp-file registry so 'Clear all' genuinely frees disk, not just the UI. | |
| Every PDF/ZIP scratch file goes through `new_temp`, which records the path. A | |
| later `clear_all` unlinks every recorded file. Thread-safe (a min worker pool | |
| on HF still shares this process). UI-free so `src/` stays testable. | |
| Note: this clears the *file cache* we create. Gradio's own request queue is | |
| per-request and transient (a handler can't flush other users' pending events), | |
| and the priority queue in `queue_manager` is built and drained within a single | |
| `process_pdf` call - neither leaves persistent state to clear. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import tempfile | |
| import threading | |
| _lock = threading.Lock() | |
| _tracked: set[str] = set() | |
| def new_temp(suffix: str = "") -> str: | |
| """Create a tracked temp file and return its path (handle closed).""" | |
| fd, path = tempfile.mkstemp(suffix=suffix) | |
| os.close(fd) | |
| with _lock: | |
| _tracked.add(path) | |
| return path | |
| def register(path: str) -> None: | |
| """Track an externally created path so clear_all() will remove it.""" | |
| with _lock: | |
| _tracked.add(path) | |
| def discard(path: str) -> bool: | |
| """Unlink one tracked file early (e.g. an input PDF after it's loaded). | |
| Returns True if the file was removed. Untracks regardless so a vanished | |
| file doesn't linger in the registry. | |
| """ | |
| with _lock: | |
| _tracked.discard(path) | |
| try: | |
| os.remove(path) | |
| return True | |
| except OSError: | |
| return False | |
| def clear_all() -> int: | |
| """Unlink every tracked temp file. Returns count actually removed.""" | |
| removed = 0 | |
| with _lock: | |
| # list() snapshot is required: we mutate _tracked (discard) in-loop. | |
| # Iterating the set directly -> "Set changed size during iteration". | |
| for path in list(_tracked): # NOSONAR python:S7504 false positive | |
| try: | |
| os.remove(path) | |
| removed += 1 | |
| except FileNotFoundError: | |
| pass | |
| except OSError: | |
| continue # leave it tracked; retry on next clear | |
| _tracked.discard(path) | |
| return removed | |
| def tracked_count() -> int: | |
| with _lock: | |
| return len(_tracked) | |