feat: extract opengait_studio monorepo module
Move demo implementation into opengait_studio, retire Sports2D runtime integration, and align packaging with root-level monorepo dependency management.
This commit is contained in:
@@ -251,7 +251,7 @@ class TestNatsPublisherIntegration:
|
||||
except ImportError:
|
||||
pytest.skip("nats-py not installed")
|
||||
|
||||
from opengait.demo.output import NatsPublisher, create_result
|
||||
from opengait_studio.output import NatsPublisher, create_result
|
||||
|
||||
# Create publisher
|
||||
publisher = NatsPublisher(nats_url, subject=NATS_SUBJECT)
|
||||
@@ -341,7 +341,7 @@ class TestNatsPublisherIntegration:
|
||||
def test_nats_publisher_graceful_when_server_unavailable(self) -> None:
|
||||
"""Test that publisher handles missing server gracefully."""
|
||||
try:
|
||||
from opengait.demo.output import NatsPublisher
|
||||
from opengait_studio.output import NatsPublisher
|
||||
except ImportError:
|
||||
pytest.skip("output module not available")
|
||||
|
||||
@@ -380,7 +380,7 @@ class TestNatsPublisherIntegration:
|
||||
import asyncio
|
||||
|
||||
import nats # type: ignore[import-untyped]
|
||||
from opengait.demo.output import NatsPublisher, create_result
|
||||
from opengait_studio.output import NatsPublisher, create_result
|
||||
except ImportError as e:
|
||||
pytest.skip(f"Required module not available: {e}")
|
||||
|
||||
@@ -15,7 +15,7 @@ from numpy.typing import NDArray
|
||||
import pytest
|
||||
import torch
|
||||
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
REPO_ROOT: Final[Path] = Path(__file__).resolve().parents[2]
|
||||
SAMPLE_VIDEO_PATH: Final[Path] = REPO_ROOT / "assets" / "sample.mp4"
|
||||
@@ -31,7 +31,7 @@ def _device_for_runtime() -> str:
|
||||
def _run_pipeline_cli(
|
||||
*args: str, timeout_seconds: int = 120
|
||||
) -> subprocess.CompletedProcess[str]:
|
||||
command = [sys.executable, "-m", "opengait.demo", *args]
|
||||
command = [sys.executable, "-m", "opengait_studio", *args]
|
||||
return subprocess.run(
|
||||
command,
|
||||
cwd=REPO_ROOT,
|
||||
@@ -728,14 +728,14 @@ def test_pipeline_visualizer_updates_on_no_detection() -> None:
|
||||
This is a regression test for the window freeze issue when no person is detected.
|
||||
The window should refresh every frame to prevent freezing.
|
||||
"""
|
||||
from opengait.demo.pipeline import ScoliosisPipeline
|
||||
from opengait_studio.pipeline import ScoliosisPipeline
|
||||
|
||||
# Create a minimal pipeline with mocked dependencies
|
||||
with (
|
||||
mock.patch("opengait.demo.pipeline.YOLO") as mock_yolo,
|
||||
mock.patch("opengait.demo.pipeline.create_source") as mock_source,
|
||||
mock.patch("opengait.demo.pipeline.create_publisher") as mock_publisher,
|
||||
mock.patch("opengait.demo.pipeline.ScoNetDemo") as mock_classifier,
|
||||
mock.patch("opengait_studio.pipeline.YOLO") as mock_yolo,
|
||||
mock.patch("opengait_studio.pipeline.create_source") as mock_source,
|
||||
mock.patch("opengait_studio.pipeline.create_publisher") as mock_publisher,
|
||||
mock.patch("opengait_studio.pipeline.ScoNetDemo") as mock_classifier,
|
||||
):
|
||||
# Setup mock detector that returns no detections (causing process_frame to return None)
|
||||
mock_detector = mock.MagicMock()
|
||||
@@ -791,16 +791,16 @@ def test_pipeline_visualizer_updates_on_no_detection() -> None:
|
||||
|
||||
|
||||
def test_pipeline_visualizer_clears_bbox_on_no_detection() -> None:
|
||||
from opengait.demo.pipeline import ScoliosisPipeline
|
||||
from opengait_studio.pipeline import ScoliosisPipeline
|
||||
|
||||
# Create a minimal pipeline with mocked dependencies
|
||||
with (
|
||||
mock.patch("opengait.demo.pipeline.YOLO") as mock_yolo,
|
||||
mock.patch("opengait.demo.pipeline.create_source") as mock_source,
|
||||
mock.patch("opengait.demo.pipeline.create_publisher") as mock_publisher,
|
||||
mock.patch("opengait.demo.pipeline.ScoNetDemo") as mock_classifier,
|
||||
mock.patch("opengait.demo.pipeline.select_person") as mock_select_person,
|
||||
mock.patch("opengait.demo.pipeline.mask_to_silhouette") as mock_mask_to_sil,
|
||||
mock.patch("opengait_studio.pipeline.YOLO") as mock_yolo,
|
||||
mock.patch("opengait_studio.pipeline.create_source") as mock_source,
|
||||
mock.patch("opengait_studio.pipeline.create_publisher") as mock_publisher,
|
||||
mock.patch("opengait_studio.pipeline.ScoNetDemo") as mock_classifier,
|
||||
mock.patch("opengait_studio.pipeline.select_person") as mock_select_person,
|
||||
mock.patch("opengait_studio.pipeline.mask_to_silhouette") as mock_mask_to_sil,
|
||||
):
|
||||
# Create mock detection result for frames 0-1 (valid detection)
|
||||
mock_box = mock.MagicMock()
|
||||
@@ -919,7 +919,7 @@ def test_pipeline_visualizer_clears_bbox_on_no_detection() -> None:
|
||||
|
||||
|
||||
def test_frame_pacer_emission_count_24_to_15() -> None:
|
||||
from opengait.demo.pipeline import _FramePacer
|
||||
from opengait_studio.pipeline import _FramePacer
|
||||
|
||||
pacer = _FramePacer(15.0)
|
||||
interval_ns = int(1_000_000_000 / 24)
|
||||
@@ -928,7 +928,7 @@ def test_frame_pacer_emission_count_24_to_15() -> None:
|
||||
|
||||
|
||||
def test_frame_pacer_requires_positive_target_fps() -> None:
|
||||
from opengait.demo.pipeline import _FramePacer
|
||||
from opengait_studio.pipeline import _FramePacer
|
||||
|
||||
with pytest.raises(ValueError, match="target_fps must be positive"):
|
||||
_FramePacer(0.0)
|
||||
@@ -950,6 +950,6 @@ def test_resolve_stride_modes(
|
||||
mode: Literal["manual", "sliding", "chunked"],
|
||||
expected: int,
|
||||
) -> None:
|
||||
from opengait.demo.pipeline import resolve_stride
|
||||
from opengait_studio.pipeline import resolve_stride
|
||||
|
||||
assert resolve_stride(window, stride, mode) == expected
|
||||
@@ -8,7 +8,7 @@ import pytest
|
||||
from beartype.roar import BeartypeCallHintParamViolation
|
||||
from jaxtyping import TypeCheckError
|
||||
|
||||
from opengait.demo.preprocess import mask_to_silhouette
|
||||
from opengait_studio.preprocess import mask_to_silhouette
|
||||
|
||||
|
||||
class TestMaskToSilhouette:
|
||||
@@ -18,7 +18,7 @@ import torch
|
||||
from torch import Tensor
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
# Constants for test configuration
|
||||
CONFIG_PATH = Path("configs/sconet/sconet_scoliosis1k.yaml")
|
||||
@@ -27,7 +27,7 @@ CONFIG_PATH = Path("configs/sconet/sconet_scoliosis1k.yaml")
|
||||
@pytest.fixture
|
||||
def demo() -> "ScoNetDemo":
|
||||
"""Create ScoNetDemo without loading checkpoint (CPU-only)."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
return ScoNetDemo(
|
||||
cfg_path=str(CONFIG_PATH),
|
||||
@@ -71,7 +71,7 @@ class TestScoNetDemoConstruction:
|
||||
|
||||
def test_construction_from_config_no_checkpoint(self) -> None:
|
||||
"""Test construction with config only, no checkpoint."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
demo = ScoNetDemo(
|
||||
cfg_path=str(CONFIG_PATH),
|
||||
@@ -87,7 +87,7 @@ class TestScoNetDemoConstruction:
|
||||
|
||||
def test_construction_with_relative_path(self) -> None:
|
||||
"""Test construction handles relative config path correctly."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
demo = ScoNetDemo(
|
||||
cfg_path="configs/sconet/sconet_scoliosis1k.yaml",
|
||||
@@ -100,7 +100,7 @@ class TestScoNetDemoConstruction:
|
||||
|
||||
def test_construction_invalid_config_raises(self) -> None:
|
||||
"""Test construction raises with invalid config path."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
with pytest.raises((FileNotFoundError, TypeError)):
|
||||
_ = ScoNetDemo(
|
||||
@@ -180,7 +180,7 @@ class TestScoNetDemoPredict:
|
||||
self, demo: "ScoNetDemo", dummy_sils_single: Tensor
|
||||
) -> None:
|
||||
"""Test predict returns (str, float) tuple with valid label."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
result_raw = demo.predict(dummy_sils_single)
|
||||
result = cast(tuple[str, float], result_raw)
|
||||
@@ -217,7 +217,7 @@ class TestScoNetDemoNoDDP:
|
||||
|
||||
def test_no_distributed_init_in_construction(self) -> None:
|
||||
"""Test that construction does not call torch.distributed."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
with patch("torch.distributed.is_initialized") as mock_is_init:
|
||||
with patch("torch.distributed.init_process_group") as mock_init_pg:
|
||||
@@ -327,14 +327,14 @@ class TestScoNetDemoLabelMap:
|
||||
|
||||
def test_label_map_has_three_classes(self) -> None:
|
||||
"""Test LABEL_MAP has exactly 3 classes."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
assert len(ScoNetDemo.LABEL_MAP) == 3
|
||||
assert set(ScoNetDemo.LABEL_MAP.keys()) == {0, 1, 2}
|
||||
|
||||
def test_label_map_values_are_valid_strings(self) -> None:
|
||||
"""Test LABEL_MAP values are valid non-empty strings."""
|
||||
from opengait.demo.sconet_demo import ScoNetDemo
|
||||
from opengait_studio.sconet_demo import ScoNetDemo
|
||||
|
||||
for value in ScoNetDemo.LABEL_MAP.values():
|
||||
assert isinstance(value, str)
|
||||
@@ -7,14 +7,14 @@ from unittest import mock
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from opengait.demo.input import create_source
|
||||
from opengait.demo.visualizer import (
|
||||
from opengait_studio.input import create_source
|
||||
from opengait_studio.visualizer import (
|
||||
DISPLAY_HEIGHT,
|
||||
DISPLAY_WIDTH,
|
||||
ImageArray,
|
||||
OpenCVVisualizer,
|
||||
)
|
||||
from opengait.demo.window import select_person
|
||||
from opengait_studio.window import select_person
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
SAMPLE_VIDEO_PATH = REPO_ROOT / "assets" / "sample.mp4"
|
||||
@@ -8,7 +8,7 @@ import pytest
|
||||
import torch
|
||||
from numpy.typing import NDArray
|
||||
|
||||
from opengait.demo.window import SilhouetteWindow, select_person
|
||||
from opengait_studio.window import SilhouetteWindow, select_person
|
||||
|
||||
|
||||
class TestSilhouetteWindow:
|
||||
Reference in New Issue
Block a user