diff --git a/pyproject.toml b/pyproject.toml index 1c28976..c734a1a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ [dependency-groups] dev = [ - "pytest>=8.2.2", + "pytest>=8.2.2,<9", "pytest-asyncio>=0.23.7", "pytest-mock>=3.14.0", "pytest-cov>=6.0.0", diff --git a/t4_devkit/viewer/viewer.py b/t4_devkit/viewer/viewer.py index c0b315a..72a73b5 100644 --- a/t4_devkit/viewer/viewer.py +++ b/t4_devkit/viewer/viewer.py @@ -99,6 +99,14 @@ def _set_time_seconds(timeline: EntityPath, seconds: float) -> None: rr.set_time(timeline, timestamp=seconds) +def _encoded_image(path: str): + """Create an encoded image archetype across supported Rerun SDK versions.""" + if RERUN_SDK_VERSION < (0, 28): + return rr.ImageEncoded(path=path) + else: + return rr.EncodedImage(path=path) + + class RerunViewer: """A viewer class that renders some components powered by rerun.""" @@ -462,7 +470,7 @@ def render_image(self, seconds: float, camera: str, image: str | NDArrayU8) -> N _set_time_seconds(EntityPath.TIMELINE, seconds) entity_path = format_entity(EntityPath.BASE_LINK, camera) - entity = rr.ImageEncoded(path=image) if isinstance(image, str) else rr.Image(image) + entity = _encoded_image(image) if isinstance(image, str) else rr.Image(image) rr.log(entity_path, entity) diff --git a/tests/viewer/test_viewer.py b/tests/viewer/test_viewer.py index 2594a3f..d69e25e 100644 --- a/tests/viewer/test_viewer.py +++ b/tests/viewer/test_viewer.py @@ -1,11 +1,13 @@ from __future__ import annotations import numpy as np +import pytest from pyquaternion import Quaternion from t4_devkit.dataclass import LidarPointCloud from t4_devkit.schema import CalibratedSensor, EgoPose, Sensor from t4_devkit.viewer import EntityPath, format_entity +from t4_devkit.viewer import viewer as viewer_module def test_format_entity() -> None: @@ -91,6 +93,31 @@ def test_render_image(dummy_viewer, dummy_camera_calibration) -> None: dummy_viewer.render_image(seconds=seconds, camera="camera", image=dummy_image) +@pytest.mark.parametrize( + ("rerun_sdk_version", "archetype_name"), + [((0, 27), "ImageEncoded"), ((0, 28), "EncodedImage")], +) +def test_render_encoded_image( + dummy_viewer, monkeypatch, rerun_sdk_version: tuple[int, int], archetype_name: str +) -> None: + """Test rendering encoded images with old and new Rerun archetype names.""" + paths = [] + + class EncodedImage: + def __init__(self, *, path: str) -> None: + paths.append(path) + + monkeypatch.delattr(viewer_module.rr, "EncodedImage", raising=False) + monkeypatch.delattr(viewer_module.rr, "ImageEncoded", raising=False) + monkeypatch.setattr(viewer_module.rr, archetype_name, EncodedImage, raising=False) + monkeypatch.setattr(viewer_module.rr, "log", lambda *_args, **_kwargs: None) + monkeypatch.setattr(viewer_module, "RERUN_SDK_VERSION", rerun_sdk_version) + + dummy_viewer.render_image(seconds=1.0, camera="camera", image="image.jpg") + + assert paths == ["image.jpg"] + + def test_render_ego(dummy_viewer) -> None: """Test rendering ego pose with `RerunViewer`.""" seconds = 1.0 # [sec]