Skip to content

Commit f61f108

Browse files
committed
Add finite check and improve compatibility tests
dlc_processor: broaden validate_pose_array signature to accept source_backend as PoseBackends|str and add a check_finite option (default True) that raises on non-finite values to catch invalid pose outputs early. tests: make torch stubbing more robust by using importlib.util.find_spec in tests/compat/conftest.py; update tests/compat/test_dlclive_package_compat.py to refine _get_signature_params typing, import Parameter, and handle constructors that accept **kwargs more gracefully (provide clearer diagnostic when expected GUI kwargs may be passed through). tox.ini: add a [testenv:dlclive] passenv block for DLCLIVE test env vars and propagate that passenv to dlclive-pypi and dlclive-github envs so DLCLive compatibility tests pick up required environment variables.
1 parent 5c03b4e commit f61f108

4 files changed

Lines changed: 31 additions & 7 deletions

File tree

dlclivegui/services/dlc_processor.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ class PosePacket:
6161
raw: Any | None = None
6262

6363

64-
def validate_pose_array(pose: Any, *, source_backend: PoseBackends = PoseBackends.DLC_LIVE) -> np.ndarray:
64+
def validate_pose_array(
65+
pose: Any, *, source_backend: PoseBackends | str = PoseBackends.DLC_LIVE, check_finite: bool = True
66+
) -> np.ndarray:
6567
"""
6668
Validate pose output shape and dtype.
6769
@@ -101,6 +103,9 @@ def validate_pose_array(pose: Any, *, source_backend: PoseBackends = PoseBackend
101103
f"{source_backend} returned an invalid pose output format: expected numeric values, got dtype={arr.dtype}"
102104
)
103105

106+
if check_finite and not np.isfinite(arr).all():
107+
raise ValueError(f"{source_backend} returned an invalid pose output format: contains non-finite values")
108+
104109
return arr
105110

106111

tests/compat/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# tests/compat/conftest.py
2+
import importlib.util
23
import sys
34
import types
45

56
# Stub out torch imports to avoid ImportError when torch is not installed in DLCLive package.
67
# This allows testing of DLCLive API compatibility without requiring torch.
78
# Ideally imports should be guarded in the package itself, but this is a pragmatic solution for now.
89
# IMPORTANT NOTE: This should ideally be removed and replaced whenever possible.
9-
if "torch" not in sys.modules:
10+
if importlib.util.find_spec("torch") is None:
1011
sys.modules["torch"] = types.ModuleType("torch")

tests/compat/test_dlclive_package_compat.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@
33
import importlib.metadata
44
import inspect
55
import os
6+
from collections.abc import Mapping
7+
from inspect import Parameter
68
from pathlib import Path
79

810
import numpy as np
911
import pytest
1012

1113

12-
def _get_signature_params(callable_obj) -> tuple[set[str], bool]:
14+
def _get_signature_params(callable_obj) -> tuple[Mapping[str, Parameter], bool]:
1315
"""
14-
Return allowed keyword names for callable, allowing for **kwargs.
16+
Return allowed keyword names for callable and whether it accepts **kwargs.
1517
1618
Example:
1719
>>> params, accepts_var_kw = _get_signature_params(lambda x, y, **kwargs: None, {"x", "y"})
18-
>>> params == {"x", "y"}
19-
True
20+
>>> sorted(params)
21+
['x', 'y', 'kwargs']
2022
>>> accepts_var_kw
2123
True
2224
"""
@@ -53,13 +55,20 @@ def test_dlclive_constructor_accepts_gui_expected_kwargs():
5355
"single_animal",
5456
"device",
5557
}
56-
params, _ = _get_signature_params(DLCLive.__init__)
58+
params, accepts_var_kw = _get_signature_params(DLCLive.__init__)
5759
params = {
5860
name
5961
for name, p in params.items()
6062
if p.kind in (inspect.Parameter.KEYWORD_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD)
6163
}
6264
missing = {name for name in expected if name not in params}
65+
if missing and accepts_var_kw:
66+
# DLCLive.__init__ accepts **kwargs, so GUI-passed kwargs are still supported.
67+
raise AssertionError(
68+
f"DLCLive.__init__ is missing expected kwargs called by GUI: {sorted(missing)}, "
69+
"but accepts **kwargs so may still be compatible. "
70+
"Please verify that these kwargs are passed through and update this test if so."
71+
)
6372
assert not missing, f"DLCLive.__init__ is missing expected kwargs called by GUI: {sorted(missing)}"
6473

6574

tox.ini

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,16 @@ passenv =
4747
; ruff check .
4848
; ruff format --check .
4949

50+
[testenv:dlclive]
51+
passenv =
52+
DLCLIVE_TEST_MODEL_PATH
53+
DLCLIVE_TEST_MODEL_TYPE
54+
5055
# Run locally : tox -e dlclive-pypi
5156
[testenv:dlclive-pypi]
5257
description = DLCLive compatibility tests against specific PyPi release
58+
passenv =
59+
{[testenv:dlclive]passenv}
5360
deps =
5461
deeplabcut-live==1.1
5562
commands =
@@ -58,6 +65,8 @@ commands =
5865
# Run locally : tox -e dlclive-github
5966
[testenv:dlclive-github]
6067
description = DLCLive compatibility tests against GitHub main
68+
passenv =
69+
{[testenv:dlclive]passenv}
6170
deps =
6271
git+https://github.com/DeepLabCut/DeepLabCut-live.git@main
6372
commands =

0 commit comments

Comments
 (0)