Skip to content

client.project_assets

Bases: SyncResource

Sync project asset-scope namespace (client.project_assets).

batch_add

batch_add(project_id: UUID | str, *, asset_ids: list[UUID | str]) -> BatchAddResult

Sync-add up to 1000 explicit asset_ids to this project's scope (Manager+). Idempotent — ids already in scope come back as skipped. For larger / filter-driven selections use :meth:bulk_add.

Raises:

Type Description
PayloadTooLargeError

asset_ids exceeds 1000 (PAYLOAD_TOO_LARGE).

NotFoundError

unknown project (PROJECT_NOT_FOUND).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

empty asset_ids (VALIDATION_ERROR).

batch_remove

batch_remove(project_id: UUID | str, *, asset_ids: list[UUID | str]) -> BatchRemoveResult

Sync-remove up to 1000 explicit asset_ids from this project's scope (Manager+). Cascade-wipes annotations / comments / labeling-time for the matched (project, asset) pairs in one transaction. Idempotent — ids not in the project come back as skipped. For larger selections use :meth:bulk_remove.

Raises:

Type Description
PayloadTooLargeError

asset_ids exceeds 1000 (PAYLOAD_TOO_LARGE).

NotFoundError

unknown project (PROJECT_NOT_FOUND).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

empty asset_ids (VALIDATION_ERROR).

batch_delete_annotations

batch_delete_annotations(project_id: UUID | str, *, asset_ids: list[UUID | str], class_ids: list[UUID | str] | None = None, source: AnnotationSource | str | None = None) -> BatchDeleteAnnotationsResult

Sync-delete the annotations of up to 1000 explicit asset_ids (Manager+, ADR-0103), optionally narrowed by class_ids (IN) and/or source (manual | imported | model). Locked shapes are never deleted — they're reported in skipped_locked. Idempotent.

DOUBLE cap: the request 413s when EITHER the asset_ids list exceeds 1000 OR the selection matches more than 1000 non-locked annotations (the sync budget bounds deleted rows). Use :meth:bulk_delete_annotations for either overflow.

Raises:

Type Description
PayloadTooLargeError

asset_ids > 1000, or matched annotations > 1000 (PAYLOAD_TOO_LARGE).

NotFoundError

unknown project (PROJECT_NOT_FOUND).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

empty asset_ids, empty class_ids, or an unknown predicate key (VALIDATION_ERROR — the body forbids extras).

bulk_add

bulk_add(project_id: UUID | str, *, asset_ids: list[UUID | str] | None = None, filter: AssetFilterParam | None = None, exclude_asset_ids: list[UUID | str] | None = None, idempotency_key: str | None = None) -> JobHandle

Kick off an async add of assets to this project's scope (Manager+); returns a :class:JobHandle (202). Pass EXACTLY ONE of asset_ids or filter (an AssetFilter — dataset-scoped: q filename substring / created_at_from / created_at_to / uploaded_by / status / content_type); exclude_asset_ids is filter-mode only. Idempotent on (project, asset) collisions — already-in-scope rows count as skipped.

Raises:

Type Description
ConflictError

idempotency key reused with a different body (IDEMPOTENCY_REPLAY).

RateLimitError

per-tenant active-job cap reached (JOB_PER_TENANT_CAP).

NotFoundError

unknown project (PROJECT_NOT_FOUND).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

neither/both of asset_ids/filter, empty asset_ids, or excludes with asset_ids (VALIDATION_ERROR).

bulk_remove

bulk_remove(project_id: UUID | str, *, asset_ids: list[UUID | str] | None = None, filter: ProjectFilterParam | None = None, exclude_asset_ids: list[UUID | str] | None = None, idempotency_key: str | None = None) -> JobHandle

Kick off an async remove of assets from this project's scope (Manager+); returns a :class:JobHandle (202). The worker cascade-wipes per-(project, asset) annotations / comments / labeling-time in one transaction. Pass EXACTLY ONE of asset_ids or filter (a ProjectFilter — workflow + tags + metadata); exclude_asset_ids (filter-mode only) is critical here for the "remove all matching except these" UX. Idempotent.

Raises:

Type Description
ConflictError

idempotency key reused with a different body (IDEMPOTENCY_REPLAY).

RateLimitError

per-tenant active-job cap reached (JOB_PER_TENANT_CAP).

NotFoundError

unknown project (PROJECT_NOT_FOUND).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

neither/both of asset_ids/filter, empty asset_ids, or excludes with asset_ids (VALIDATION_ERROR).

bulk_delete_annotations

bulk_delete_annotations(project_id: UUID | str, *, asset_ids: list[UUID | str] | None = None, filter: ProjectFilterParam | None = None, exclude_asset_ids: list[UUID | str] | None = None, class_ids: list[UUID | str] | None = None, source: AnnotationSource | str | None = None, idempotency_key: str | None = None) -> JobHandle

Kick off an async delete of the annotations on selected assets (Manager+, ADR-0103); returns a :class:JobHandle (202). Pass EXACTLY ONE of asset_ids or filter (a ProjectFilter); exclude_asset_ids is filter-mode only. Narrow the annotations with class_ids (IN) and/or source (manual | imported | model — e.g. model to undo an auto-label run without touching human work). Locked shapes are never deleted; the count lands on the job's result_summary["skipped_locked"] (present only when non-zero). job.total counts matched non-locked annotations.

Raises:

Type Description
ConflictError

idempotency key reused with a different body (IDEMPOTENCY_REPLAY).

RateLimitError

per-tenant active-job cap reached (JOB_PER_TENANT_CAP).

NotFoundError

unknown project (PROJECT_NOT_FOUND).

ForbiddenError

caller is not a project manager (AUTH_FORBIDDEN).

UnprocessableError

neither/both of asset_ids/filter, empty asset_ids, empty class_ids, excludes with asset_ids, or an unknown predicate key (VALIDATION_ERROR — the body forbids extras).

Response models

Models returned by client.project_assets methods (fields, types, and what each means).

Project-scope membership + annotation-clear envelopes (ADR-0103 / ADR-0041).

A project owns a subset of its dataset's assets (project_asset_state). The resource in resources.project_assets mutates that membership (add/remove) and clears annotations off scoped assets, in two flavors:

  • async bulk-* kickoffs return a Job (see types.jobs) — no model here; the per-kind result_summary (e.g. {"skipped_locked": n} for bulk-delete-annotations) is a plain dict on Job.
  • sync batch-* ops return the canonical batch envelope modeled below: total == <changed> + skipped over the requested asset ids, one results entry per requested id (ADR-0041).

Response models only (extra="allow"); request bodies are built as dicts in the resource. Every field is a primitive — this module depends on no other type module.

BatchAddResultItem

Bases: BaseModel

Per-asset outcome of a sync batch_add. skipped = already in the project's scope (idempotent re-add) or not a ready asset of this dataset.

BatchAddResult

Bases: BaseModel

Sync batch-op envelope (ADR-0041): total == added + skipped and len(results) == total. skipped = already-in-scope ids.

BatchRemoveResultItem

Bases: BaseModel

Per-asset outcome of a sync batch_remove. skipped = the id was not in the project, so there was nothing to drop.

BatchRemoveResult

Bases: BaseModel

Sync batch-op envelope (ADR-0041): total == removed + skipped and len(results) == total. Removing cascade-wipes per-(project, asset) annotations / comments / labeling-time in one transaction.

BatchDeleteAnnotationsResultItem

Bases: BaseModel

Per-asset outcome of a sync batch_delete_annotations. cleared = at least one annotation deleted on this asset; skipped = nothing matched (no annotations, predicate matched none, or every match was locked). deleted counts annotations removed on this id.

BatchDeleteAnnotationsResult

Bases: BaseModel

Sync batch-op envelope for annotation clears (ADR-0103): total == cleared + skipped counts ASSETS, len(results) == total; the annotation-level accounting is carried by deleted_annotations and skipped_locked (matched shapes left in place because they're locked, ADR-0084).