Skip to content

Commit e94ffb9

Browse files
authored
Merge pull request #54 from DeepLabCut/cy/pre-release-cleanup
Pre-release cleanup for PySide6 GUI
2 parents 1a795b9 + af06d09 commit e94ffb9

File tree

23 files changed

+724
-315
lines changed

23 files changed

+724
-315
lines changed

.github/workflows/testing-ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
pull_request:
55
types: [opened, synchronize, reopened]
66

7+
concurrency:
8+
group: ci-${{ github.workflow }}-pr-${{ github.event.pull_request.number }}
9+
cancel-in-progress: true
10+
711
jobs:
812
unit:
913
name: Unit + Smoke (no hardware) • ${{ matrix.os }} • py${{ matrix.python }}
@@ -38,6 +42,17 @@ jobs:
3842
python -m pip install -U pip wheel
3943
python -m pip install -U tox tox-gh-actions
4044
45+
- name: Install Qt/OpenGL runtime deps (Ubuntu)
46+
if: startsWith(matrix.os, 'ubuntu')
47+
run: |
48+
sudo apt-get update
49+
sudo apt-get install -y \
50+
libegl1 \
51+
libgl1 \
52+
libopengl0 \
53+
libxkbcommon-x11-0 \
54+
libxcb-cursor0
55+
4156
- name: Run tests (exclude hardware) with coverage via tox
4257
run: |
4358
tox -q
@@ -54,6 +69,7 @@ jobs:
5469
echo '```' >> "$GITHUB_STEP_SUMMARY"
5570
5671
- name: Upload coverage to Codecov
72+
if: github.event_name == 'pull_request' && (github.base_ref == 'main' || github.base_ref == 'master')
5773
uses: codecov/codecov-action@v5
5874
with:
5975
files: ./coverage.xml

dlclivegui/__init__.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,13 @@
77
MultiCameraSettings,
88
RecordingSettings,
99
)
10-
from .gui.camera_config.camera_config_dialog import CameraConfigDialog
11-
from .gui.main_window import DLCLiveMainWindow
1210
from .main import main
13-
from .services.multi_camera_controller import MultiCameraController, MultiFrameData
1411

1512
__all__ = [
1613
"ApplicationSettings",
1714
"CameraSettings",
1815
"DLCProcessorSettings",
1916
"MultiCameraSettings",
2017
"RecordingSettings",
21-
"DLCLiveMainWindow",
22-
"MultiCameraController",
23-
"MultiFrameData",
24-
"CameraConfigDialog",
2518
"main",
2619
]
27-
__version__ = "2.0.0rc0" # PLACEHOLDER

dlclivegui/cameras/backends/opencv_backend.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
)
2626

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

3029
if TYPE_CHECKING:
3130
from dlclivegui.config import CameraSettings
@@ -169,7 +168,7 @@ def open(self) -> None:
169168
ns["device_pid"] = int(chosen.pid)
170169
if chosen.name:
171170
ns["device_name"] = chosen.name
172-
logger.info("Persisted OpenCV device_id=%s", chosen.stable_id)
171+
logger.debug("Persisted OpenCV device_id=%s", chosen.stable_id)
173172

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

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

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

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

435-
logger.info(
434+
logger.debug(
436435
"Resolution requested=%s, actual=%s",
437436
f"{req_w}x{req_h}" if (req_w > 0 and req_h > 0) else "Auto",
438437
f"{actual_res[0]}x{actual_res[1]}" if actual_res else "unknown",

dlclivegui/config.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import annotations
33

44
import json
5+
from enum import Enum
56
from pathlib import Path
67
from typing import Any, Literal
78

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

1416

1517
class CameraSettings(BaseModel):
@@ -239,14 +241,46 @@ class DLCProcessorSettings(BaseModel):
239241
resize: float = Field(default=1.0, gt=0)
240242
precision: Precision = "FP32"
241243
additional_options: dict[str, Any] = Field(default_factory=dict)
242-
model_type: Literal["pytorch"] = "pytorch"
244+
model_type: ModelType = "pytorch"
243245
single_animal: bool = True
244246

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

252+
@field_validator("model_type", mode="before")
253+
@classmethod
254+
def _coerce_model_type(cls, v):
255+
"""
256+
Accept:
257+
- "pytorch"/"tensorflow"/etc as strings
258+
- Enum instances (e.g. Engine.PYTORCH) and store their .value
259+
Always return a lowercase string.
260+
"""
261+
if v is None or v == "":
262+
return "pytorch"
263+
264+
# If caller passed Engine enum or any Enum, use its value
265+
if isinstance(v, Enum):
266+
v = v.value
267+
268+
# If caller passed something with a `.value` attribute (defensive)
269+
if not isinstance(v, str) and hasattr(v, "value"):
270+
v = v.value
271+
272+
if not isinstance(v, str):
273+
raise TypeError(f"model_type must be a string or Enum, got {type(v)!r}")
274+
275+
v = v.strip().lower()
276+
277+
# Optional: enforce allowed values
278+
allowed = {"pytorch", "tensorflow"}
279+
if v not in allowed:
280+
raise ValueError(f"Unknown model type: {v!r}. Allowed: {sorted(allowed)}")
281+
282+
return v
283+
250284

251285
class BoundingBoxSettings(BaseModel):
252286
enabled: bool = False

0 commit comments

Comments
 (0)