diff --git a/src/lerobot/scripts/lerobot_annotate.py b/src/lerobot/scripts/lerobot_annotate.py index 579175052..41fede908 100644 --- a/src/lerobot/scripts/lerobot_annotate.py +++ b/src/lerobot/scripts/lerobot_annotate.py @@ -28,7 +28,12 @@ For distributed runs, see ``examples/annotations/run_hf_job.py``. """ import logging +from contextlib import suppress from pathlib import Path +from typing import TYPE_CHECKING + +from huggingface_hub import HfApi, snapshot_download +from huggingface_hub.errors import RevisionNotFoundError from lerobot.annotations.steerable_pipeline.config import AnnotationPipelineConfig from lerobot.annotations.steerable_pipeline.executor import Executor @@ -42,6 +47,12 @@ from lerobot.annotations.steerable_pipeline.validator import StagingValidator from lerobot.annotations.steerable_pipeline.vlm_client import make_vlm_client from lerobot.annotations.steerable_pipeline.writer import LanguageColumnsWriter from lerobot.configs import parser +from lerobot.utils.import_utils import _datasets_available, require_package + +if TYPE_CHECKING or _datasets_available: + from lerobot.datasets.dataset_metadata import CODEBASE_VERSION + from lerobot.datasets.io_utils import load_info + from lerobot.datasets.utils import create_lerobot_dataset_card logger = logging.getLogger(__name__) @@ -50,8 +61,6 @@ def _resolve_root(cfg: AnnotationPipelineConfig) -> Path: if cfg.root is not None: return Path(cfg.root) if cfg.repo_id is not None: - from huggingface_hub import snapshot_download - return Path(snapshot_download(repo_id=cfg.repo_id, repo_type="dataset")) raise ValueError("Either --root or --repo_id must be provided.") @@ -125,10 +134,7 @@ def _push_to_hub(root: Path, cfg: AnnotationPipelineConfig) -> None: Pushes to ``cfg.new_repo_id`` when set, otherwise back to ``cfg.repo_id``. """ - from huggingface_hub import HfApi # noqa: PLC0415 - - from lerobot.datasets.io_utils import load_info # noqa: PLC0415 - from lerobot.datasets.utils import create_lerobot_dataset_card # noqa: PLC0415 + require_package("datasets", "dataset") repo_id = cfg.new_repo_id or cfg.repo_id commit_message = cfg.push_commit_message or "Add steerable annotations (lerobot-annotate)" @@ -163,8 +169,6 @@ def _push_to_hub(root: Path, cfg: AnnotationPipelineConfig) -> None: # ``RevisionNotFoundError``. Read the version straight from the # dataset's own ``meta/info.json`` so we tag whatever the writer # actually wrote (no accidental drift if the codebase floor moves). - from lerobot.datasets.dataset_metadata import CODEBASE_VERSION # noqa: PLC0415 - version_tag = ( dataset_info.codebase_version if dataset_info.codebase_version.startswith("v") else CODEBASE_VERSION ) @@ -178,10 +182,6 @@ def _push_to_hub(root: Path, cfg: AnnotationPipelineConfig) -> None: tag_kwargs["revision"] = revision try: - from contextlib import suppress # noqa: PLC0415 - - from huggingface_hub.errors import RevisionNotFoundError # noqa: PLC0415 - with suppress(RevisionNotFoundError): api.delete_tag(repo_id, tag=version_tag, repo_type="dataset") api.create_tag(**tag_kwargs) diff --git a/tests/scripts/test_lerobot_annotate.py b/tests/scripts/test_lerobot_annotate.py index 03f1ee104..b1db997e3 100644 --- a/tests/scripts/test_lerobot_annotate.py +++ b/tests/scripts/test_lerobot_annotate.py @@ -18,6 +18,8 @@ import json from types import SimpleNamespace import pytest +import requests +from huggingface_hub.errors import RevisionNotFoundError # ``lerobot.scripts.lerobot_annotate`` (and the ``_push_to_hub`` path it # exercises) imports ``lerobot.datasets``, which only ships under the @@ -26,7 +28,7 @@ pytest.importorskip("datasets", reason="datasets is required (install lerobot[da def test_push_to_hub_tags_uploaded_dataset_revision(tmp_path, monkeypatch): - from lerobot.scripts.lerobot_annotate import _push_to_hub + from lerobot.scripts import lerobot_annotate root = tmp_path / "dataset" (root / "meta").mkdir(parents=True) @@ -45,9 +47,6 @@ def test_push_to_hub_tags_uploaded_dataset_revision(tmp_path, monkeypatch): return SimpleNamespace(oid="abc123") def delete_tag(self, repo_id, **kwargs): - import requests - from huggingface_hub.errors import RevisionNotFoundError - calls["delete_tag"] = {"repo_id": repo_id, **kwargs} # Simulate the common case: no stale tag to delete. raise RevisionNotFoundError("no such tag", response=requests.Response()) @@ -55,7 +54,7 @@ def test_push_to_hub_tags_uploaded_dataset_revision(tmp_path, monkeypatch): def create_tag(self, **kwargs): calls["create_tag"] = kwargs - monkeypatch.setattr("huggingface_hub.HfApi", FakeHfApi) + monkeypatch.setattr(lerobot_annotate, "HfApi", FakeHfApi) def fake_card_push(self, **kwargs): calls["card_push"] = {"content": str(self), **kwargs} @@ -69,7 +68,7 @@ def test_push_to_hub_tags_uploaded_dataset_revision(tmp_path, monkeypatch): push_commit_message=None, ) - _push_to_hub(root, cfg) + lerobot_annotate._push_to_hub(root, cfg) assert calls["create_repo"] == { "repo_id": "annotated/dataset",