Run update check in a separate thread by mikhailmikhalchuk · Pull Request #3234 · DeepLabCut/DeepLabCut
and others added 2 commits
March 9, 2026 18:29Introduce a non-blocking update check and in-app updater. Key changes: - deeplabcut/gui/utils.py: add check_pypi_version, is_latest_deeplabcut_version/is_latest_plugin_version, and UpdateCheckWorker (Qt QObject) to fetch PyPI info with timeouts and packaging-aware version comparison; handle network errors gracefully. - deeplabcut/gui/window.py: replace the blocking _check_for_updates flow with a Qt-threaded update check (schedule_update_check, _start_update_check) that uses UpdateCheckWorker; add UI handling for results, prompt to update and run pip installs via QProcess, and cancel/cleanup on exit. Removed previous blocking imports/usages (subprocess, threading, call_with_timeout). - deeplabcut/utils/multiprocessing.py: mark call_with_timeout as deprecated for update checks (note only), since it's no longer used for update checking. Why: make update checking robust and non-blocking, avoid freezing the GUI, support plugin/version checks, provide an integrated, user-friendly update flow with proper error handling. Co-Authored-By: Mikhail Mikhalchuk <59270079+mikhailmikhalchuk@users.noreply.github.com>
Accumulate and surface output from the pip update QProcess so users get live feedback and the full output after the process finishes. Added a _update_process_output list, initialized when starting/tearing down updates, and a helper _drain_update_process_output() that reads available data, appends it to the buffer, logs the latest non-empty line and shows it in the status bar. The finished handler now drains remaining output, builds the final output by joining the buffer, and resets the buffer and status message. Also added a clarifying comment in utils.py about making the plugin check optional in the future.
Replace the old thread/worker based update check with a single QtNetwork-backed UpdateChecker that issues async HTTP requests to PyPI for both deeplabcut and napari-deeplabcut, enforces a QTimer timeout, aggregates results, and supports silent/manual checks and cancellation. Integrate the new checker into MainWindow (use DLC and NAPARI_DLC __version__ imports), simplify scheduling, and connect finished signal to the existing handler. Also add safer shutdown handling (_closing flag), drain update process output, and minor UI/version label updates.
Remove network-related imports and functions used for checking package versions on PyPI. Deleted parse_version, check_pypi_version, is_latest_deeplabcut_version and is_latest_plugin_version, and removed unused imports (re, socket, urllib.request, urllib.error.URLError, Tuple). Also add a Callable type annotation to Worker.__init__ and clean up imports in gui/utils.py.
Make UpdateChecker more robust by ignoring reply callbacks when not running, recording the first network error message, and safely cleaning up QNetworkReply objects. Replies now have their finished signal disconnected (errors from disconnect are caught), running replies are aborted and deleted, and the replies map is cleared. Also emit a shallow copy of the result dict to avoid downstream mutation after emission.
Replace singleShot scheduling with a dedicated QTimer to manage update checks. Adds _update_check_timer and _scheduled_update_check_silent to schedule, supersede, and run delayed checks via check_for_updates(..., delay_ms). Wire up startup and menu actions to the new API and stop the timer during shutdown. This prevents overlapping checks, allows cancelation on close, and centralizes delayed-check logic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters