Skip to content

Upgrade PySide6 multi-camera GUI#38

Open
C-Achard wants to merge 100 commits intomasterfrom
cy/pre-release-fixes-2.0
Open

Upgrade PySide6 multi-camera GUI#38
C-Achard wants to merge 100 commits intomasterfrom
cy/pre-release-fixes-2.0

Conversation

@C-Achard
Copy link

@C-Achard C-Achard commented Jan 30, 2026

Finalizing the PySide6+multi-camera GUI

Further refinement of GUI added in #35 by @arturoptophys

Features

  • Full project file tree refactor for more granularity and ease of use
  • Typed configs
  • Improved settings UX/UI Works as is, delayed
  • Theme/UI alignment with DLC, icons, colors, etc
  • Improved camera loading UX and validation
  • Many fixes to OpenCV backend
  • Finish config refactor
  • Fixes all issues in Pre-release fixes & improvements checklist #37

Also tweaks error handling, UI and UX.


Additional TODOs

  • Documentation overhaul ->see Create 2.0 documentation #39
  • Comprehensive unit and GUI test suite, >80% coverage (49% current)
    • In particular, video recording coverage is very low currently¨
    • Camera backends unit/smoke test

arturoptophys and others added 30 commits October 21, 2025 11:22
…modern-python-and-pyqt6

Add Basler and GenTL camera backends for modular capture
…camera-functionality

Rework layout and camera handling controls
…r integration

- Implemented `get_device_count` method in `GenTLCameraBackend` to retrieve the number of GenTL devices detected.
- Added `max_devices` configuration option in `CameraSettings` to limit device probing.
- Introduced `BoundingBoxSettings` for bounding box visualization, integrated into the main GUI.
- Enhanced `DLCLiveProcessor` to accept a processor instance during configuration.
- Updated GUI to support processor selection and auto-recording based on processor commands.
- Refactored camera properties handling and removed deprecated advanced properties editor.
- Improved error handling and logging for processor connections and recording states.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Add new unit tests for processor utilities and the BaseProcessorSocket: tests/custom_processors/test_base_processor.py (tests BaseProcessorSocket init/stop, recording flags, process behavior, broadcasting error handling) and tests/custom_processors/test_builtin_discovery_utils.py (tests scanning/loading/instantiation/display of processor modules). Also tweak tests/services/test_dlc_processor.py to increase qtbot.waitUntil timeout from 1500 to 5000ms with a comment to reduce flakiness due to scheduling delays.
Delete dlclivegui/cameras/config_adapters.py which contained the ensure_dc_camera helper that normalized CameraSettings from a dataclass, Pydantic CameraSettingsModel, or dict. This removes redundant/unused adapter code as part of a config cleanup/restructure; normalization logic is no longer required in this location.
Introduce a reusable splash screen implementation and integrate it into the app entrypoint. Added dlclivegui/gui/misc/splash.py with SplashConfig, build_splash_pixmap and show_splash (handles missing images with a filled fallback pixmap). Exposed splash-related constants in theme.py and updated main.py to use SplashConfig/show_splash, keep a reference to the main window on the app object, and use the QApplication attribute enum member for HiDPI. Added tests/tests/gui/test_app_entrypoint.py to mock Qt classes and verify both valid-image and fallback splash behavior, timer handling, and that the main window is shown.
Comment out explicit QApplication.setAttribute(A A_UseHighDpiPixmaps) because Qt6 enables HiDPI pixmaps by default, so the attribute no longer needs to be set.
If the splash image is invalid or missing, build_splash_pixmap now returns None (disabling the splash) and show_splash returns None accordingly. main() is updated to guard splash.close() when no splash was created. Tests updated to reflect the new splash API: test_app_entrypoint rewritten to use the centralized show_splash mock and renamed tests, a new test_splash_screen module verifies build_splash_pixmap valid/fallback behavior, and a small qtbot.wait(5) was added to test_dlc_processor to reduce flakiness.
Introduce session and run naming for recordings and wire up UI/persistence and path planning.

- UI: add session name field, "use timestamp" checkbox, and a recording path preview; persist last session name and update preview on changes. Hook session name/timestamp into recording start and processor auto-start behavior.
- Recording manager: create session/run directories (timestamped or incrementing run_NNNN), store session/run paths, write per-camera files into the run directory, return the run dir on start (or None on failure), and better handle partial start failures. stop_all clears session/run state.
- Utils: add sanitize_name, timestamp_string, split_stem_ext, next_run_index, build_run_dir and build_recording_plan + RecordingPlan dataclass to centralize filename and directory logic.
- Minor: small module header cleanup in settings_store.

These changes make recording output paths deterministic and user-configurable (timestamped or sequential), improve UX with a live preview, and centralize run-dir/file planning logic.
Restore and persist the "Use timestamp" checkbox state, wire a dedicated handler to update the preview and save the setting. Update preview to show the filename stem (Path.stem) for clarity. Remove the old _recording_plan_from_ui and dependency on build_recording_plan in the main window; use RecordingManager run_dir directly and return early if starting fails.

Refactor RecordingManager.start_all signature and behavior: accept a session_name (sanitized) and use_timestamp flag, add an all_or_nothing option for atomic starts, build session/run dirs from the recording output path, and simplify error/log handling. Minor cleanup: iterate recorders consistently, clear session/run dirs on stop, and adjust stats formatting/import placement.

Also reorder imports and remove an explicit prefix argument when calling next_run_index in build_run_dir.
Add comprehensive GUI tests for recording path preview, persistence, and start-recording behavior (tests/gui/test_recording_paths_ui.py). Enhance tests/gui/conftest.py with autouse fixtures to isolate QSettings (so tests don't touch real user settings), a start_all_spy that monkeypatches RecordingManager.start_all to capture arguments and return a deterministic fake run_dir, and a fake_processor fixture for processor-driven behavior. Clean up unused/commented imports and whitespace in conftest. Make a tiny, non-functional cleanup in dlclivegui/gui/recording_manager.py around cam_path assignment.
Add comprehensive unit tests for RecordingManager and VideoRecorder. New tests cover recorder lifecycle (start/stop), frame-size inference, timestamp handling, partial vs all-or-nothing startup behavior, stats aggregation, and error handling. Extend tests/gui/conftest.py with test helpers and fixtures: FakeVideoRecorder, recording_settings, patch_video_recorder, and patch_build_run_dir to avoid invoking vidgear/ffmpeg and to provide deterministic run directories. Add tests/services/test_video_recorder.py with a FakeWriteGear double and tests for writer construction, gray->RGB conversion, float scaling, queue/drop behavior, timestamps sidecar JSON, and encoder error propagation.
Delete the setuptools-based setup.py since we have pyproject.toml now
Remove legacy dlclivegui/config.py and switch to typed models in dlclivegui.utils.config_models (rename ApplicationSettings, CameraSettings, DLCProcessorSettings, MultiCameraSettings, RecordingSettings to ApplicationSettingsModel, CameraSettingsModel, DLCProcessorSettingsModel, MultiCameraSettingsModel, RecordingSettingsModel). Update package exports and camera/main_window imports accordingly. Move ModelPathStore into dlclivegui.utils.settings_store (add QSettings-based persistence, path normalization and helpers) and import it from main_window. Also add is_model_file usage and Path handling in the new settings store.
Move dlclivegui/utils/config_models.py -> dlclivegui/config.py and rename Pydantic model types (e.g. CameraSettingsModel -> CameraSettings, MultiCameraSettingsModel -> MultiCameraSettings, DLCProcessorSettingsModel -> DLCProcessorSettings, RecordingSettingsModel -> RecordingSettings, BoundingBoxSettingsModel -> BoundingBoxSettings, VisualizationSettingsModel -> VisualizationSettings, ApplicationSettingsModel -> ApplicationSettings). Update imports, type hints and factory/controller/GUI code to use the new module and class names, adjust DEFAULT_CONFIG, and update tests accordingly. This is a refactor to centralize config models under dlclivegui.config and propagate the new names throughout the codebase.
Add a menu action and UI button to open the recording folder in the system file explorer.
Also comment out the previous automatic loading of myconfig.json (replace FIXME with NOTE/TODO) to avoid silently loading config on startup.
Combine container/codec UI into a compact row, use RecordingSettings.crf as the default CRF and add a tooltip. Add a "Record video with overlays" checkbox and implement _render_overlays_for_recording to draw pose and bounding-box overlays into frames sent to the recorder; _on_multi_frame_ready now applies this when the checkbox is checked. Consolidate and extend test fixtures (fake DLCLive/backend factories, window fixture, recording helpers, and patched recording/video writer), add tests for overlay rendering and recording behavior, and adjust several GUI/service/unit tests with appropriate pytest marks.
Prevent the recording path preview from being squished and refactor the container/codec/CRF controls into a single responsive grid row with explicit labels, tooltips, size policies, column stretches, spacing and minimum content lengths. Set CRF spinbox range/value and tooltip, keep platform-specific codec lists, and move the "Open recording folder" button below the recording controls to avoid layout shifting. Also remove the unused bbox_color argument from the drawing call in _build_bbox_group.
Add GitHub Actions CI workflow to run unit and smoke tests across Ubuntu, macOS, and Windows for Python 3.10–3.12, cache tox environments, append coverage summary, and upload coverage to Codecov. Introduce tox.ini to standardize test and lint environments (py310/311/312 plus a ruff lint env), run pytest excluding hardware-marked tests, and set CI-friendly environment variables. Add .coveragerc to configure coverage (branch, source dlclivegui, and omit hardware SDK shim backends). Update pyproject.toml test markers to add a "hardware" marker and comment out the previous "slow" marker.
Add comprehensive tests for camera backends: aravis and OpenCV (tests/cameras/backends/*). Introduce a backend-specific pytest conftest that detects optional dependencies, provides --run-hardware gating, and supplies fixtures to reset registry or force fake/unavailable SDKs. Include extensive fake Aravis/OpenCV helpers to exercise read/open/close/configure paths. Also apply two tiny tweaks: add a file-identifying comment in dlclivegui/cameras/factory.py and remove an unused bbox_color parameter from tests/conftest.py.
Add comprehensive unit tests for dlclivegui.utils.display and dlclivegui.utils.stats, covering tiling geometry, tiled frame creation, drawing utilities (bbox, keypoints, pose), and stats formatting. Introduce property-based tests using Hypothesis for recorder and DLC stats formatting and several exact-case tests. Also update pyproject.toml to include hypothesis>=6.0 in dev and test dependencies.
Rename QtSettingsStore to DLCLiveGUISettingsStore and add recording-related settings: get/set for session_name and get/set for use_timestamp (with robust parsing of stored types). Also add comprehensive unit tests: tests for the settings store (including snapshot save/load and model path store behaviors) and many utility tests (is_model_file, sanitize_name, timestamp_string, split_stem_ext, run indexing, build_run_dir, build_recording_plan, and FPSTracker). Includes an InMemoryQSettings test helper.
Introduce DLCLiveGUISettingsStore and use it throughout the GUI to persist/load settings (session name, timestamp preference, last config path, full config snapshot). Replace ad-hoc QSettings helpers in main_window with calls to the new store, save snapshots/last-path when loading/saving configs, and wire session/timestamp persistence to the store. Replace internal DLC stats formatting with shared format_dlc_stats util. Add logging/debug messages and safer path normalization to ModelPathStore. Add pragma markers for coverage around OneEuroFilter in dlc_processor_socket. Update GUI tests to isolate QSettings (use INI in tmp) and disable modal dialogs during tests to avoid native crashes in CI.
Reword the comment describing potential issues when a QTimer-triggered validation opens a modal QMessageBox while the parent window is closing. Replace the Windows-specific phrasing with a more general note about errors with unpredictable timing (heap corruption / access violations). No functional change; tests/CI mitigation guidance remains.
Add support for persisting original DeepLabCut pose data as an HDF5 alongside the existing .pkl save. Introduces a dlc_cfg attribute and set_dlc_cfg() on BaseProcessorSocket, a save_original_pose() helper that builds a pandas DataFrame (with MultiIndex columns when bodyparts are present) and writes to <name>_DLC.hdf5, and includes dlc_cfg in the saved payload. The processor.save() flow now pops original_pose out of the pickle and delegates HDF5 writing when save_original is enabled. DLCLiveProcessor now passes its cfg to the processor during initialization. Tests updated/added to validate HDF5 creation, labeled/unlabeled columns, and dlc_cfg inclusion.
@C-Achard C-Achard mentioned this pull request Feb 5, 2026
6 tasks
@C-Achard C-Achard added the help wanted Extra attention is needed label Feb 5, 2026
@C-Achard C-Achard marked this pull request as ready for review February 5, 2026 15:44
@C-Achard C-Achard requested a review from deruyter92 February 5, 2026 15:44
@C-Achard
Copy link
Author

C-Achard commented Feb 5, 2026

@arturoptophys I cannot request your review directly, but if you have time to have a look would be much appreciated !
An early docs draft is also available at #39

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request help wanted Extra attention is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants