Skip to content

Commit c3d23e3

Browse files
committed
Add camera backend tests and fixtures
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.
1 parent d050d98 commit c3d23e3

File tree

5 files changed

+850
-1
lines changed

5 files changed

+850
-1
lines changed

dlclivegui/cameras/factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Backend discovery and construction utilities."""
22

3+
# dlclivegui/cameras/factory.py
34
from __future__ import annotations
45

56
import copy

tests/cameras/backends/conftest.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# tests/cameras/backends/conftest.py
2+
import importlib
3+
import os
4+
5+
import pytest
6+
7+
8+
# -----------------------------
9+
# Dependency detection helpers
10+
# -----------------------------
11+
def _has_module(name: str) -> bool:
12+
try:
13+
importlib.import_module(name)
14+
return True
15+
except Exception:
16+
return False
17+
18+
19+
ARAVIS_AVAILABLE = _has_module("gi") # Aravis via GObject introspection
20+
PYPYLON_AVAILABLE = _has_module("pypylon") # Basler pypylon SDK
21+
22+
23+
# -----------------------------
24+
# Pytest configuration
25+
# -----------------------------
26+
def pytest_addoption(parser: pytest.Parser) -> None:
27+
parser.addoption(
28+
"--run-hardware",
29+
action="store_true",
30+
default=False,
31+
help="Run tests that require hardware/SDKs (aravis/pypylon/gentl). "
32+
"By default these are skipped. You can also set BACKENDS_RUN_HARDWARE=1.",
33+
)
34+
35+
36+
def pytest_configure(config: pytest.Config) -> None:
37+
# Document custom markers
38+
config.addinivalue_line("markers", "hardware: tests that touch real devices or SDKs")
39+
config.addinivalue_line("markers", "aravis: tests for Aravis backend")
40+
config.addinivalue_line("markers", "pypylon: tests for Basler/pypylon backend")
41+
42+
43+
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
44+
"""
45+
Auto-skip tests if the corresponding dependency is not present,
46+
and only run hardware-marked tests when explicitly requested.
47+
"""
48+
run_hardware_flag = bool(config.getoption("--run-hardware"))
49+
run_hardware_env = os.getenv("BACKENDS_RUN_HARDWARE", "").strip() in {"1", "true", "yes"}
50+
run_hardware = run_hardware_flag or run_hardware_env
51+
52+
skip_no_aravis = pytest.mark.skip(reason="Aravis/gi is not available")
53+
skip_no_pypylon = pytest.mark.skip(reason="Basler pypylon is not available")
54+
skip_hardware = pytest.mark.skip(
55+
reason="Hardware/SDK tests disabled. Use --run-hardware or set BACKENDS_RUN_HARDWARE=1"
56+
)
57+
58+
for item in items:
59+
# Per-backend availability skips
60+
if "aravis" in item.keywords and not ARAVIS_AVAILABLE:
61+
item.add_marker(skip_no_aravis)
62+
if "pypylon" in item.keywords and not PYPYLON_AVAILABLE:
63+
item.add_marker(skip_no_pypylon)
64+
65+
# Global hardware gate (only applies to tests marked 'hardware')
66+
if "hardware" in item.keywords and not run_hardware:
67+
item.add_marker(skip_hardware)
68+
69+
70+
# -----------------------------
71+
# Useful fixtures for backends
72+
# -----------------------------
73+
@pytest.fixture
74+
def reset_backend_registry():
75+
"""
76+
Ensure backend registry is clean for tests that rely on registration behavior.
77+
Automatically imports the package module that registers backends.
78+
"""
79+
from dlclivegui.cameras.base import reset_backends
80+
81+
reset_backends()
82+
try:
83+
# Import once so decorators run and register built-ins where possible.
84+
import dlclivegui.cameras.backends # noqa: F401
85+
except Exception:
86+
# If import fails (optional deps), tests can still register backends directly.
87+
pass
88+
yield
89+
reset_backends() # cleanup
90+
91+
92+
@pytest.fixture
93+
def force_aravis_unavailable(monkeypatch):
94+
"""
95+
Force the Aravis backend to behave as if Aravis is not installed.
96+
Useful for testing error paths without modifying the environment.
97+
"""
98+
import dlclivegui.cameras.backends.aravis_backend as ar
99+
100+
# Simulate missing optional dependency
101+
monkeypatch.setattr(ar, "ARAVIS_AVAILABLE", False, raising=False)
102+
# Make sure the module symbol itself is treated as absent
103+
monkeypatch.setattr(ar, "Aravis", None, raising=False)
104+
yield
105+
106+
107+
@pytest.fixture
108+
def force_pypylon_unavailable(monkeypatch):
109+
"""
110+
Force Basler/pypylon to be unavailable for error-path testing.
111+
"""
112+
try:
113+
import dlclivegui.cameras.backends.basler_backend as bas
114+
except Exception:
115+
# If the module doesn't exist in your tree, ignore.
116+
yield
117+
return
118+
monkeypatch.setattr(bas, "PYPYLON_AVAILABLE", False, raising=False)
119+
monkeypatch.setattr(bas, "pylon", None, raising=False)
120+
yield

0 commit comments

Comments
 (0)