|
2 | 2 |
|
3 | 3 | import queue |
4 | 4 | import threading |
| 5 | +from types import SimpleNamespace |
5 | 6 |
|
6 | 7 | import numpy as np |
7 | 8 | import pytest |
|
10 | 11 |
|
11 | 12 | # from dlclivegui.config import DLCProcessorSettings |
12 | 13 | from dlclivegui.processors.processor_utils import ProcessorSpec |
13 | | -from dlclivegui.services.dlc_processor import ( |
14 | | - DLCLiveProcessor, |
15 | | -) |
| 14 | +from dlclivegui.services.dlc_processor import DLCLiveProcessor |
16 | 15 | from dlclivegui.services.inference.base import ( |
17 | 16 | ProcessorStats, |
18 | 17 | WorkerState, |
@@ -385,3 +384,97 @@ def test_queue_accounting_clears_after_processed_frame(qtbot, monkeypatch_dlcliv |
385 | 384 |
|
386 | 385 | finally: |
387 | 386 | proc.reset() |
| 387 | + |
| 388 | + |
| 389 | +def test_load_pose_metadata_from_dlc_config() -> None: |
| 390 | + processor = DLCLiveProcessor() |
| 391 | + processor._dlc = SimpleNamespace( |
| 392 | + cfg={ |
| 393 | + "Task": "mouse", |
| 394 | + "bodyparts": [ |
| 395 | + "nose", |
| 396 | + "shoulder", |
| 397 | + "tail", |
| 398 | + ], |
| 399 | + "skeleton": [ |
| 400 | + ["nose", "shoulder"], |
| 401 | + ["shoulder", "tail"], |
| 402 | + ], |
| 403 | + } |
| 404 | + ) |
| 405 | + |
| 406 | + processor._load_pose_metadata_from_dlc_config() |
| 407 | + |
| 408 | + assert processor._keypoint_names == ( |
| 409 | + "nose", |
| 410 | + "shoulder", |
| 411 | + "tail", |
| 412 | + ) |
| 413 | + assert processor._skeleton_id == "deeplabcut.mouse" |
| 414 | + assert processor._skeleton_edges == ( |
| 415 | + ("nose", "shoulder"), |
| 416 | + ("shoulder", "tail"), |
| 417 | + ) |
| 418 | + |
| 419 | + |
| 420 | +def test_metadata_loader_clears_stale_metadata() -> None: |
| 421 | + processor = DLCLiveProcessor() |
| 422 | + processor._keypoint_names = ("stale",) |
| 423 | + processor._skeleton_id = "stale" |
| 424 | + processor._skeleton_edges = (("stale", "other"),) |
| 425 | + processor._dlc = SimpleNamespace(cfg={}) |
| 426 | + |
| 427 | + processor._load_pose_metadata_from_dlc_config() |
| 428 | + |
| 429 | + assert processor._keypoint_names is None |
| 430 | + assert processor._skeleton_id is None |
| 431 | + assert processor._skeleton_edges is None |
| 432 | + |
| 433 | + |
| 434 | +def test_metadata_loader_allows_bodyparts_without_skeleton() -> None: |
| 435 | + processor = DLCLiveProcessor() |
| 436 | + processor._dlc = SimpleNamespace( |
| 437 | + cfg={ |
| 438 | + "bodyparts": ["nose", "tail"], |
| 439 | + } |
| 440 | + ) |
| 441 | + |
| 442 | + processor._load_pose_metadata_from_dlc_config() |
| 443 | + |
| 444 | + assert processor._keypoint_names == ( |
| 445 | + "nose", |
| 446 | + "tail", |
| 447 | + ) |
| 448 | + assert processor._skeleton_id is None |
| 449 | + assert processor._skeleton_edges is None |
| 450 | + |
| 451 | + |
| 452 | +def test_metadata_loader_rejects_duplicate_bodyparts() -> None: |
| 453 | + processor = DLCLiveProcessor() |
| 454 | + processor._dlc = SimpleNamespace( |
| 455 | + cfg={ |
| 456 | + "bodyparts": ["nose", "nose"], |
| 457 | + } |
| 458 | + ) |
| 459 | + |
| 460 | + with pytest.raises( |
| 461 | + RuntimeError, |
| 462 | + match="duplicate", |
| 463 | + ): |
| 464 | + processor._load_pose_metadata_from_dlc_config() |
| 465 | + |
| 466 | + |
| 467 | +def test_metadata_loader_rejects_unknown_skeleton_endpoint() -> None: |
| 468 | + processor = DLCLiveProcessor() |
| 469 | + processor._dlc = SimpleNamespace( |
| 470 | + cfg={ |
| 471 | + "bodyparts": ["nose", "tail"], |
| 472 | + "skeleton": [["nose", "shoulder"]], |
| 473 | + } |
| 474 | + ) |
| 475 | + |
| 476 | + with pytest.raises( |
| 477 | + RuntimeError, |
| 478 | + match="unknown bodypart", |
| 479 | + ): |
| 480 | + processor._load_pose_metadata_from_dlc_config() |
0 commit comments