fix(jobs): handle str-typed job stage from huggingface_hub

inspect_job's status.stage is an enum (with .value) in some
huggingface_hub versions and a plain str in others. The poller
assumed the enum shape, raising "'str' object has no attribute
'value'" on resume for users on the str-returning version.

Read it via getattr(..., "value", ...) so both shapes work, and
parametrize the poll test over enum and str stages so the str case
is actually exercised (the old mock only ever simulated the enum).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nicolas Rabault
2026-06-26 17:03:53 +02:00
parent 3e0e349d0a
commit f5cc9f5963
2 changed files with 9 additions and 5 deletions
+2 -1
View File
@@ -206,7 +206,8 @@ def _poll_until_done(
try:
info = inspect_job(job_id=job_id)
failures = 0
stage = info.status.stage.value
# `stage` is an enum in some huggingface_hub versions and a plain str in others.
stage = getattr(info.status.stage, "value", info.status.stage)
if stage in _TERMINAL_STAGES:
if status_holder is not None:
status_holder["message"] = getattr(info.status, "message", None)
+7 -4
View File
@@ -41,12 +41,15 @@ def test_resolve_job_tags_always_includes_lerobot_and_dedups():
assert resolve_job_tags(["lelab", "lerobot", "lelab"]) == ["lerobot", "lelab"]
def _fake_inspect(stage_value):
return lambda job_id: SimpleNamespace(status=SimpleNamespace(stage=SimpleNamespace(value=stage_value)))
def _fake_inspect(stage_value, *, as_enum=True):
# huggingface_hub returns `stage` as an enum (with `.value`) in some versions and a plain str in others.
stage = SimpleNamespace(value=stage_value) if as_enum else stage_value
return lambda job_id: SimpleNamespace(status=SimpleNamespace(stage=stage))
def test_poll_until_done_returns_terminal_stage(monkeypatch):
monkeypatch.setattr("lerobot.jobs.hf.inspect_job", _fake_inspect("COMPLETED"))
@pytest.mark.parametrize("as_enum", [True, False], ids=["enum_stage", "str_stage"])
def test_poll_until_done_returns_terminal_stage(monkeypatch, as_enum):
monkeypatch.setattr("lerobot.jobs.hf.inspect_job", _fake_inspect("COMPLETED", as_enum=as_enum))
done = threading.Event()
assert _poll_until_done("j", done, poll_interval=0.01) == "COMPLETED"
assert done.is_set()