Skip to content

Commit ba20dac

Browse files
committed
Add basic compatibility tests for deeplabcut-live API
1 parent 08ba8a4 commit ba20dac

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed

.github/workflows/testing-ci.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,40 @@ jobs:
7575
token: ${{ secrets.CODECOV_TOKEN }}
7676
files: ./coverage.xml
7777
fail_ci_if_error: false
78+
79+
dlclive-compat:
80+
name: DLCLive Compatibility • ${{ matrix.label }} • py${{ matrix.python }}
81+
runs-on: ubuntu-latest
82+
strategy:
83+
fail-fast: false
84+
matrix:
85+
python: ['3.11']
86+
include:
87+
- label: pypi-1.1
88+
dlclive_spec: deeplabcut-live==1.1
89+
- label: github-main
90+
dlclive_spec: git+https://github.com/DeepLabCut/DeepLabCut-live.git@main
91+
92+
steps:
93+
- name: Checkout
94+
uses: actions/checkout@v6
95+
96+
- name: Set up Python
97+
uses: actions/setup-python@v6
98+
with:
99+
python-version: ${{ matrix.python }}
100+
cache: 'pip'
101+
102+
- name: Install package + test dependencies
103+
run: |
104+
python -m pip install -U pip wheel
105+
python -m pip install -e .[test]
106+
107+
- name: Install matrix DLCLive build
108+
run: |
109+
python -m pip install --upgrade --force-reinstall "${{ matrix.dlclive_spec }}"
110+
python -m pip show deeplabcut-live
111+
112+
- name: Run DLCLive compatibility tests
113+
run: |
114+
python -m pytest -m dlclive_compat tests/compat/test_dlclive_package_compat.py -q

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ markers = [
115115
"unit: Unit tests for individual components",
116116
"integration: Integration tests for component interaction",
117117
"functional: Functional tests for end-to-end workflows",
118+
"dlclive_compat: Package/API compatibility tests against supported dlclive versions",
118119
"hardware: Tests that require specific hardware, notable camera backends",
119120
# "slow: Tests that take a long time to run",
120121
"gui: Tests that require GUI interaction",
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from __future__ import annotations
2+
3+
import importlib.metadata
4+
import inspect
5+
6+
import pytest
7+
8+
9+
def _get_signature_params(callable_obj) -> tuple[set[str], bool]:
10+
"""
11+
Return allowed keyword names for callable, allowing for **kwargs.
12+
13+
Example:
14+
>>> params, accepts_var_kw = _get_signature_params(lambda x, y, **kwargs: None, {"x", "y"})
15+
>>> params == {"x", "y"}
16+
True
17+
>>> accepts_var_kw
18+
True
19+
"""
20+
sig = inspect.signature(callable_obj)
21+
params = sig.parameters
22+
accepts_var_kw = any(p.kind == inspect.Parameter.VAR_KEYWORD for p in params.values())
23+
return params, accepts_var_kw
24+
25+
26+
@pytest.mark.dlclive_compat
27+
def test_dlclive_package_is_importable():
28+
from dlclive import DLCLive # noqa: PLC0415
29+
30+
assert DLCLive is not None
31+
# Helpful for CI logs to confirm matrix install result.
32+
_ = importlib.metadata.version("deeplabcut-live")
33+
34+
35+
@pytest.mark.dlclive_compat
36+
def test_dlclive_constructor_accepts_gui_expected_kwargs():
37+
"""
38+
GUI passes these kwargs when constructing DLCLive.
39+
This test catches upstream API changes that would break initialization.
40+
"""
41+
from dlclive import DLCLive # noqa: PLC0415
42+
43+
expected = {
44+
"model_path",
45+
"model_type",
46+
"processor",
47+
"dynamic",
48+
"resize",
49+
"precision",
50+
"single_animal",
51+
"device",
52+
}
53+
params, accepts_var_kw = _get_signature_params(DLCLive.__init__)
54+
missing = {name for name in expected if name not in params}
55+
assert not missing, f"DLCLive.__init__ is missing expected kwargs called by GUI: {sorted(missing)}"
56+
assert accepts_var_kw, "DLCLive.__init__ should accept **kwargs" # captures current behavior
57+
58+
59+
@pytest.mark.dlclive_compat
60+
def test_dlclive_methods_match_gui_usage():
61+
"""
62+
GUI expects:
63+
- init_inference(frame)
64+
- get_pose(frame, frame_time=<float>)
65+
"""
66+
from dlclive import DLCLive # noqa: PLC0415
67+
68+
assert hasattr(DLCLive, "init_inference"), "DLCLive must provide init_inference(frame)"
69+
assert hasattr(DLCLive, "get_pose"), "DLCLive must provide get_pose(frame, frame_time=...)"
70+
71+
init_params, _ = _get_signature_params(DLCLive.init_inference)
72+
init_missing = {name for name in {"frame"} if name not in init_params}
73+
assert not init_missing, f"DLCLive.init_inference signature mismatch, missing: {sorted(init_missing)}"
74+
75+
get_pose_params, _ = _get_signature_params(DLCLive.get_pose)
76+
get_pose_missing = {name for name in {"frame", "frame_time"} if name not in get_pose_params}
77+
assert not get_pose_missing, f"DLCLive.get_pose signature mismatch, missing: {sorted(get_pose_missing)}"

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extras = test
1313

1414
# Keep behavior aligned with your GitHub Actions job:
1515
commands =
16-
pytest -m "not hardware" --maxfail=1 --disable-warnings \
16+
pytest -m "not hardware and not dlclive_compat" --maxfail=1 --disable-warnings \
1717
--cov=dlclivegui --cov-report=xml --cov-report=term-missing {posargs}
1818

1919
# Helpful defaults for headless CI runs (Qt/OpenCV):

0 commit comments

Comments
 (0)