fix(cron): don't crash on cron list when a job's repeat is null
Some checks failed
Docker Build and Publish / build-amd64 (push) Waiting to run
Docker Build and Publish / build-arm64 (push) Waiting to run
Docker Build and Publish / merge (push) Blocked by required conditions
Lint (ruff + ty) / ruff + ty diff (push) Waiting to run
Lint (ruff + ty) / ruff enforcement (blocking) (push) Waiting to run
Lint (ruff + ty) / Windows footguns (blocking) (push) Waiting to run
Nix / nix (macos-latest) (push) Waiting to run
Nix / nix (ubuntu-latest) (push) Waiting to run
Tests / test (1) (push) Waiting to run
Tests / test (2) (push) Waiting to run
Tests / test (3) (push) Waiting to run
Tests / test (4) (push) Waiting to run
Tests / test (5) (push) Waiting to run
Tests / test (6) (push) Waiting to run
Tests / save-durations (push) Blocked by required conditions
Tests / e2e (push) Waiting to run
Skills Index Freshness Check / check-freshness (push) Has been cancelled
Some checks failed
Docker Build and Publish / build-amd64 (push) Waiting to run
Docker Build and Publish / build-arm64 (push) Waiting to run
Docker Build and Publish / merge (push) Blocked by required conditions
Lint (ruff + ty) / ruff + ty diff (push) Waiting to run
Lint (ruff + ty) / ruff enforcement (blocking) (push) Waiting to run
Lint (ruff + ty) / Windows footguns (blocking) (push) Waiting to run
Nix / nix (macos-latest) (push) Waiting to run
Nix / nix (ubuntu-latest) (push) Waiting to run
Tests / test (1) (push) Waiting to run
Tests / test (2) (push) Waiting to run
Tests / test (3) (push) Waiting to run
Tests / test (4) (push) Waiting to run
Tests / test (5) (push) Waiting to run
Tests / test (6) (push) Waiting to run
Tests / save-durations (push) Blocked by required conditions
Tests / e2e (push) Waiting to run
Skills Index Freshness Check / check-freshness (push) Has been cancelled
`cron_list` read `job.get("repeat", {})`, but the dict-default only
applies to a MISSING key. A one-shot job persisted with `"repeat": null`
returns None, and the next `.get("times")` raised AttributeError, taking
down the whole `cron list` output. Coalesce with `or {}` so a
present-but-null repeat renders as ∞ like the other cron readers already
do. Adds a regression test.
Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
This commit is contained in:
@ -81,7 +81,10 @@ def cron_list(show_all: bool = False):
|
||||
state = job.get("state", "scheduled" if job.get("enabled", True) else "paused")
|
||||
next_run = job.get("next_run_at", "?")
|
||||
|
||||
repeat_info = job.get("repeat", {})
|
||||
# `repeat` may be present-but-null in the job record (e.g. a one-shot
|
||||
# job persisted with "repeat": null), so coalesce to {} rather than
|
||||
# relying on the dict-default, which only applies to a missing key.
|
||||
repeat_info = job.get("repeat") or {}
|
||||
repeat_times = repeat_info.get("times")
|
||||
repeat_completed = repeat_info.get("completed", 0)
|
||||
repeat_str = f"{repeat_completed}/{repeat_times}" if repeat_times else "∞"
|
||||
|
||||
@ -111,3 +111,19 @@ class TestCronCommandLifecycle:
|
||||
assert jobs[0]["skills"] == ["blogwatcher", "maps"]
|
||||
assert jobs[0]["name"] == "Skill combo"
|
||||
assert jobs[0]["profile"] == "default"
|
||||
|
||||
def test_list_does_not_crash_when_repeat_is_null(self, tmp_cron_dir, capsys):
|
||||
"""A one-shot job can be persisted with ``"repeat": null``. `cron
|
||||
list` must render it as ∞ rather than crashing on .get(...)\\.get."""
|
||||
from cron.jobs import load_jobs, save_jobs
|
||||
|
||||
create_job(prompt="One shot", schedule="every 1h")
|
||||
# Force the present-but-null shape that .get("repeat", {}) mishandles.
|
||||
jobs = load_jobs()
|
||||
jobs[0]["repeat"] = None
|
||||
save_jobs(jobs)
|
||||
|
||||
cron_command(Namespace(cron_command="list", all=True))
|
||||
|
||||
out = capsys.readouterr().out
|
||||
assert "Repeat: ∞" in out
|
||||
|
||||
Reference in New Issue
Block a user