Jobs
One view of every job your organization is running - list, read, wait for and cancel training, auto-annotation, workflow runs, evaluations, exports and imports.
Long-running work in Pictograph comes in many kinds: training runs, batch
auto-annotation, workflow runs, model evaluations, exports, and the background jobs
behind imports, video frame extraction and bulk image operations. Each kind has its own
status call on its own resource. client.jobs answers “what am I waiting on?” across all
of them at once.
Every job reads the same way, whatever its kind:
type-training,auto_annotate,workflow_run,evaluation,export, or a background job’s own type (connector_import,public_dataset_import,video_extract,batch_move, …).status- one vocabulary for every kind:queuedandrunningare active,completed,failedandcancelledare finished.progress- 0 to 100.detail- what only that kind has: a training run’s epochs, a workflow run’s frames, a background job’s item counts.cancel_path- the API route that cancels the job, orNonewhen it is finished or its kind cannot be cancelled through the API.
The list is scoped to the API key’s organization, and any role can read it. Finished background jobs (imports, extractions, bulk operations) are kept 30 days; training runs, workflow runs, batch auto-annotation and evaluations keep their history.
list
Your organization’s jobs, newest first. Queued and running jobs by default.
Source: Jobs.list
| Arg | Type | Default | Notes |
|---|---|---|---|
status |
str |
"active" |
active, finished, all, or one of queued, running, completed, failed, cancelled |
type |
str | None |
None |
Only jobs of this kind |
page_size |
int |
50 |
Jobs per request, maximum 100 |
max_total |
int | None |
None |
Stop after this many jobs |
for job in client.jobs.list():
print(job.type, job.status, job.progress, job.name)
failed = list(client.jobs.list(status="failed", type="training", max_total=20))
pictograph jobs list
pictograph jobs list --status failed --type training --limit 20
curl -s "https://api.pictograph.io/api/v1/developer/jobs?status=failed&type=training&limit=20&offset=0" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns OffsetPager[Job]
Job · 12 fields
class Job(BaseModel):
"""One job, whatever kind of work it is."""
id: str
type: str
status: str
progress: float | None = None
name: str | None = None
dataset_id: str | None = None
error: str | None = None
created_at: datetime | None = None
updated_at: datetime | None = None
completed_at: datetime | None = None
cancel_path: str | None = None
detail: dict[str, Any] = {}
The API reads at most the newest 1,000 jobs of one filter (offset + limit up to 1000);
narrow with status or type past that.
get
One job, by the id the work answered when it started: a training run’s id, an import’s id, a workflow run’s id, and so on. Either spelling of a uuid works.
Source: Jobs.get
| Arg | Type | Default | Notes |
|---|---|---|---|
job_id |
str |
required | The job’s id |
job = client.jobs.get(
job_id="c1c1c1c1-0000-4000-8000-000000000002",
)
print(job.type, job.status, job.progress, job.error)
pictograph jobs get c1c1c1c1-0000-4000-8000-000000000002
curl -s "https://api.pictograph.io/api/v1/developer/jobs/c1c1c1c1-0000-4000-8000-000000000002" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns Job
Job · 12 fields
class Job(BaseModel):
"""One job, whatever kind of work it is."""
id: str
type: str
status: str
progress: float | None = None
name: str | None = None
dataset_id: str | None = None
error: str | None = None
created_at: datetime | None = None
updated_at: datetime | None = None
completed_at: datetime | None = None
cancel_path: str | None = None
detail: dict[str, Any] = {}
Another organization’s job returns 404, like an id that does not exist.
wait
Poll a job until it finishes. Returns the completed job; raises when it failed or was cancelled.
Source: Jobs.wait
| Arg | Type | Default | Notes |
|---|---|---|---|
job_id |
str |
required | The job’s id |
poll_interval |
float |
3.0 |
Seconds between status checks |
timeout |
float |
3600.0 |
Seconds to wait. The job keeps running after it |
sleep |
Callable | None |
None |
Injectable sleep (tests) |
from pictograph.exceptions import ApiError, PollTimeoutError
try:
job = client.jobs.wait(
job_id="c1c1c1c1-0000-4000-8000-000000000002",
timeout=1800,
)
except ApiError as err:
print(err.code, err.response["error"]) # job_failed or job_cancelled
except PollTimeoutError:
print("still running - wait again later")
pictograph jobs wait c1c1c1c1-0000-4000-8000-000000000002 --timeout 1800
# REST: poll the job until its status is completed, failed or cancelled
curl -s "https://api.pictograph.io/api/v1/developer/jobs/c1c1c1c1-0000-4000-8000-000000000002" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns Job
Job · 12 fields
class Job(BaseModel):
"""One job, whatever kind of work it is."""
id: str
type: str
status: str
progress: float | None = None
name: str | None = None
dataset_id: str | None = None
error: str | None = None
created_at: datetime | None = None
updated_at: datetime | None = None
completed_at: datetime | None = None
cancel_path: str | None = None
detail: dict[str, Any] = {}
The CLI exits 0 when the job completed, non-zero when it failed or was cancelled, and 10
when it was still running at --timeout.
cancel
Cancel a queued or running job. The cancel goes through the route that cancels its kind, with that kind’s own rules: a training run is refunded what it did not use, and a cancelled workflow run keeps its outputs so far, its time on its endpoint billed as uptime. The answer is the job as it reads after the cancel.
Source: Jobs.cancel
| Arg | Type | Default | Notes |
|---|---|---|---|
job_id |
str |
required | The job’s id |
job = client.jobs.cancel(
job_id="c1c1c1c1-0000-4000-8000-000000000002",
)
print(job.status)
pictograph jobs cancel c1c1c1c1-0000-4000-8000-000000000002
# REST: read the job, then POST to its cancel_path
curl -s -X POST "https://api.pictograph.io/api/v1/developer/training/c1c1c1c1-0000-4000-8000-000000000002/cancel" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns Job
Job · 12 fields
class Job(BaseModel):
"""One job, whatever kind of work it is."""
id: str
type: str
status: str
progress: float | None = None
name: str | None = None
dataset_id: str | None = None
error: str | None = None
created_at: datetime | None = None
updated_at: datetime | None = None
completed_at: datetime | None = None
cancel_path: str | None = None
detail: dict[str, Any] = {}
Training runs, batch auto-annotation, workflow runs, model evaluations and V7 / Roboflow
imports can be cancelled through the API. A job whose cancel_path is None cannot:
the call raises ValidationError without sending anything.