Skip to content

Commit dbaccbb

Browse files
committed
Merge branch 'cy/gentl-cti-lock-fix' into cy/gentl-trigger-config
2 parents 3edb48c + ce587cb commit dbaccbb

18 files changed

Lines changed: 1115 additions & 172 deletions

.github/workflows/testing-ci.yml

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ jobs:
6161
libxcb-cursor0
6262
6363
- name: Run tests (exclude hardware) with coverage via tox
64+
shell: bash -eo pipefail {0}
6465
run: |
65-
tox -q | tee tox-output.log
66+
tox -q 2>&1 | tee tox-output.log
6667
6768
6869
- name: Append Coverage Summary to Job
@@ -85,3 +86,43 @@ jobs:
8586
token: ${{ secrets.CODECOV_TOKEN }}
8687
files: ./.coverage.py312.xml
8788
fail_ci_if_error: false
89+
90+
dlclive-compat:
91+
name: DLCLive Compatibility • ${{ matrix.label }}
92+
runs-on: ubuntu-latest
93+
strategy:
94+
fail-fast: false
95+
matrix:
96+
include:
97+
- label: pypi-1.1
98+
tox_env: dlclive-pypi
99+
- label: github-main
100+
tox_env: dlclive-github
101+
102+
steps:
103+
- uses: actions/checkout@v6
104+
105+
- uses: actions/setup-python@v6
106+
with:
107+
python-version: '3.12'
108+
cache: 'pip'
109+
110+
- name: Install Qt/OpenGL runtime deps (Ubuntu)
111+
run: |
112+
sudo apt-get update
113+
sudo apt-get install -y \
114+
libegl1 \
115+
libgl1 \
116+
libopengl0 \
117+
libxkbcommon-x11-0 \
118+
libxcb-cursor0
119+
120+
- name: Install tox
121+
run: |
122+
python -m pip install -U pip wheel
123+
python -m pip install -U tox tox-gh-actions
124+
125+
- name: Run DLCLive compatibility tests via tox
126+
shell: bash -eo pipefail {0}
127+
run: |
128+
tox -e ${{ matrix.tox_env }} -q

dlclivegui/cameras/backends/gentl_backend.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ def rebind_settings(cls, settings):
373373
cls._persist_serial_identity(settings, target_id_str)
374374
return settings
375375

376+
if target_id_str.startswith("fp:"):
377+
return settings # open() will match by fingerprint via _select_device → _match_device
378+
376379
# Non-serial fallback retained for older configs / fingerprint IDs.
377380
harvester = None
378381
try:

dlclivegui/cameras/backends/utils/gentl_discovery.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def __init__(self, cti_files: list[str]):
5151
self.harvester.add_file(cti)
5252
self.loaded_files.append(cti)
5353
except Exception as e:
54-
logger.exception(f"Failed to load CTI file: {cti}. Skipping.")
54+
logger.warning(f"Failed to load CTI file: {cti}. Skipping.")
5555
self.failed_files[cti] = str(e)
5656

5757
if not self.loaded_files:

dlclivegui/gui/main_window.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,17 @@ def __init__(self, config: ApplicationSettings | None = None):
196196

197197
# Validate cameras from loaded config (deferred to allow window to show first)
198198
# NOTE IMPORTANT (tests/CI): This is scheduled via a QTimer and may fire during pytest-qt teardown.
199-
QTimer.singleShot(100, self._validate_configured_cameras)
199+
# NOTE @C-Achard 2026-03-02: Handling this in closeEvent should help
200+
self._camera_validation_timer = QTimer(self)
201+
self._camera_validation_timer.setSingleShot(True)
202+
self._camera_validation_timer.timeout.connect(self._validate_configured_cameras)
203+
self._camera_validation_timer.start(100)
200204
# If validation triggers a modal QMessageBox (warning/error) while the parent window is closing,
201205
# it can cause errors with unpredictable timing (heap corruption / access violations).
202206
#
203207
# Mitigations for tests/CI:
204208
# - Disable this timer by monkeypatching _validate_configured_cameras in GUI tests
205209
# - OR monkeypatch/override _show_warning/_show_error to no-op in GUI tests (easiest)
206-
# - OR use a cancellable QTimer attribute and stop() it in closeEvent
207210

208211
def resizeEvent(self, event):
209212
super().resizeEvent(event)
@@ -1396,7 +1399,7 @@ def _on_multi_frame_ready(self, frame_data: MultiFrameData) -> None:
13961399
dlc_cam_id = selected_id
13971400
else:
13981401
dlc_cam_id = available_ids[0] if available_ids else ""
1399-
if dlc_cam_id is not None:
1402+
if dlc_cam_id:
14001403
self._inference_camera_id = dlc_cam_id
14011404
self._set_dlc_combo_to_id(dlc_cam_id)
14021405
self.statusBar().showMessage(
@@ -2044,6 +2047,8 @@ def closeEvent(self, event: QCloseEvent) -> None: # pragma: no cover - GUI beha
20442047
if self.multi_camera_controller.is_running():
20452048
self.multi_camera_controller.stop(wait=True)
20462049

2050+
if hasattr(self, "_camera_validation_timer") and self._camera_validation_timer.isActive():
2051+
self._camera_validation_timer.stop()
20472052
# Stop all multi-camera recorders
20482053
self._rec_manager.stop_all()
20492054

dlclivegui/gui/recording_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def write_frame(self, cam_id: str, frame: np.ndarray, timestamp: float | None =
139139
if not rec or not rec.is_running:
140140
return
141141
try:
142-
rec.write(frame, timestamp=timestamp or time.time())
142+
rec.write(frame, timestamp=timestamp if timestamp is not None else time.time())
143143
except Exception as exc:
144144
log.warning("Failed to write frame for %s: %s", cam_id, exc)
145145
try:

0 commit comments

Comments
 (0)