Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2784bd5
Remove module-level debug logging overrides
C-Achard Feb 20, 2026
9fd192e
Reduce log verbosity and remove auto-load message
C-Achard Feb 20, 2026
0daebba
Infer model backend from selected model path
C-Achard Feb 20, 2026
cfd67c7
Add temporary Engine enum and use in dlc_processor
C-Achard Feb 20, 2026
b6fd336
Use Engine enum and improve model detection
C-Achard Feb 20, 2026
58f6110
Use Engine enum and validate model path
C-Achard Feb 23, 2026
f495649
Update GUI tests and adjust tox config
C-Achard Feb 23, 2026
f2c5fb6
Remove GUI and multi-camera exports
C-Achard Feb 23, 2026
d8da888
Update tox.ini
C-Achard Feb 23, 2026
94a4d04
Add Qt/OpenGL deps to CI and restrict Codecov
C-Achard Feb 23, 2026
eb255db
Refactor camera scan state and loaders
C-Achard Feb 23, 2026
48b274c
CI, packaging: coverage PRs, export main, tox deps
C-Achard Feb 23, 2026
31e09d8
Normalize model_type and fix model paths
C-Achard Feb 23, 2026
e517aed
Enhance ModelPathStore path normalization tests
C-Achard Feb 23, 2026
c7b11c9
Add concurrency to testing CI workflow
C-Achard Feb 23, 2026
4865edb
Add Engine helpers for model path detection
C-Achard Feb 23, 2026
1f73c89
Ignore stale scan worker signals
C-Achard Feb 23, 2026
0b47bc4
Update testing-ci.yml
C-Achard Feb 23, 2026
1cf1945
Update engine.py
C-Achard Feb 23, 2026
6952b68
Update __init__.py
C-Achard Feb 23, 2026
559c775
Import Engine from dlclivegui.temp in tests
C-Achard Feb 23, 2026
025a18e
Pass file path for non-.pb model checks
C-Achard Feb 24, 2026
735b9a0
Add ModelType Literal and apply to model_type
C-Achard Feb 24, 2026
af06d09
Move package version to pyproject.toml
C-Achard Feb 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/testing-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
pull_request:
types: [opened, synchronize, reopened]

concurrency:
group: ci-${{ github.workflow }}-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
unit:
name: Unit + Smoke (no hardware) • ${{ matrix.os }} • py${{ matrix.python }}
Expand Down Expand Up @@ -38,6 +42,17 @@ jobs:
python -m pip install -U pip wheel
python -m pip install -U tox tox-gh-actions

- name: Install Qt/OpenGL runtime deps (Ubuntu)
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y \
libegl1 \
libgl1 \
libopengl0 \
libxkbcommon-x11-0 \
libxcb-cursor0

- name: Run tests (exclude hardware) with coverage via tox
run: |
tox -q
Expand All @@ -54,6 +69,7 @@ jobs:
echo '```' >> "$GITHUB_STEP_SUMMARY"

- name: Upload coverage to Codecov
if: github.event_name == 'pull_request' && (github.base_ref == 'main' || github.base_ref == 'master')
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
Expand Down
8 changes: 0 additions & 8 deletions dlclivegui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,13 @@
MultiCameraSettings,
RecordingSettings,
)
from .gui.camera_config.camera_config_dialog import CameraConfigDialog
from .gui.main_window import DLCLiveMainWindow
from .main import main
from .services.multi_camera_controller import MultiCameraController, MultiFrameData

__all__ = [
"ApplicationSettings",
"CameraSettings",
"DLCProcessorSettings",
"MultiCameraSettings",
"RecordingSettings",
"DLCLiveMainWindow",
"MultiCameraController",
"MultiFrameData",
"CameraConfigDialog",
"main",
]
__version__ = "2.0.0rc0" # PLACEHOLDER
7 changes: 3 additions & 4 deletions dlclivegui/cameras/backends/opencv_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
)

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG) # FIXME @C-Achard remove before release

if TYPE_CHECKING:
from dlclivegui.config import CameraSettings
Expand Down Expand Up @@ -169,7 +168,7 @@ def open(self) -> None:
ns["device_pid"] = int(chosen.pid)
if chosen.name:
ns["device_name"] = chosen.name
logger.info("Persisted OpenCV device_id=%s", chosen.stable_id)
logger.debug("Persisted OpenCV device_id=%s", chosen.stable_id)

self._capture, spec = open_with_fallbacks(index, backend_flag)

Expand Down Expand Up @@ -399,7 +398,7 @@ def _configure_capture(self) -> None:
self._actual_fps = float(self._capture.get(cv2.CAP_PROP_FPS) or 0.0)

# For clarity in logs
logger.info("Resolution requested=Auto, actual=%sx%s", self._actual_width, self._actual_height)
logger.debug("Resolution requested=Auto, actual=%sx%s", self._actual_width, self._actual_height)

elif not self._fast_start:
# Verified, robust path (tries candidates + verifies)
Expand Down Expand Up @@ -432,7 +431,7 @@ def _configure_capture(self) -> None:
if (self._actual_width or 0) > 0 and (self._actual_height or 0) > 0:
actual_res = (int(self._actual_width), int(self._actual_height))

logger.info(
logger.debug(
"Resolution requested=%s, actual=%s",
f"{req_w}x{req_h}" if (req_w > 0 and req_h > 0) else "Auto",
f"{actual_res[0]}x{actual_res[1]}" if actual_res else "unknown",
Expand Down
36 changes: 35 additions & 1 deletion dlclivegui/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import annotations

import json
from enum import Enum
from pathlib import Path
from typing import Any, Literal

Expand All @@ -10,6 +11,7 @@
Rotation = Literal[0, 90, 180, 270]
TileLayout = Literal["auto", "2x2", "1x4", "4x1"]
Precision = Literal["FP32", "FP16"]
ModelType = Literal["pytorch", "tensorflow"]


class CameraSettings(BaseModel):
Expand Down Expand Up @@ -239,14 +241,46 @@ class DLCProcessorSettings(BaseModel):
resize: float = Field(default=1.0, gt=0)
precision: Precision = "FP32"
additional_options: dict[str, Any] = Field(default_factory=dict)
model_type: Literal["pytorch"] = "pytorch"
model_type: ModelType = "pytorch"
single_animal: bool = True

@field_validator("dynamic", mode="before")
@classmethod
def _coerce_dynamic(cls, v):
return DynamicCropModel.from_tupleish(v)

@field_validator("model_type", mode="before")
@classmethod
def _coerce_model_type(cls, v):
"""
Accept:
- "pytorch"/"tensorflow"/etc as strings
- Enum instances (e.g. Engine.PYTORCH) and store their .value
Always return a lowercase string.
"""
if v is None or v == "":
return "pytorch"

# If caller passed Engine enum or any Enum, use its value
if isinstance(v, Enum):
v = v.value

# If caller passed something with a `.value` attribute (defensive)
if not isinstance(v, str) and hasattr(v, "value"):
v = v.value

if not isinstance(v, str):
raise TypeError(f"model_type must be a string or Enum, got {type(v)!r}")

v = v.strip().lower()

# Optional: enforce allowed values
allowed = {"pytorch", "tensorflow"}
if v not in allowed:
raise ValueError(f"Unknown model type: {v!r}. Allowed: {sorted(allowed)}")

return v


class BoundingBoxSettings(BaseModel):
enabled: bool = False
Expand Down
Loading