Asset module
Methods attached to the Kili client, to run actions on assets.
Source code in kili/presentation/client/asset.py
@for_all_methods(log_call, exclude=["__init__"])
class AssetClientMethods(BaseClientMethods):
"""Methods attached to the Kili client, to run actions on assets."""
# pylint: disable=too-many-arguments, redefined-builtin, too-many-locals
@overload
def assets(
self,
project_id: str,
asset_id: Optional[str] = None,
skip: int = 0,
fields: Optional[ListOrTuple[str]] = None,
asset_id_in: Optional[list[str]] = None,
asset_id_not_in: Optional[list[str]] = None,
disable_tqdm: Optional[bool] = None,
first: Optional[int] = None,
format: Optional[str] = None,
label_author_in: Optional[list[str]] = None,
label_created_at: Optional[str] = None,
label_type_in: Optional[list[LabelType]] = None,
metadata_where: Optional[dict] = None,
updated_at_gte: Optional[str] = None,
updated_at_lte: Optional[str] = None,
label_category_search: Optional[str] = None,
download_media: bool = False,
local_media_dir: Optional[str] = None,
created_at_gte: Optional[str] = None,
created_at_lte: Optional[str] = None,
honeypot_mark_gte: Optional[float] = None,
honeypot_mark_lte: Optional[float] = None,
consensus_mark_gte: Optional[float] = None,
consensus_mark_lte: Optional[float] = None,
inference_mark_gte: Optional[float] = None,
inference_mark_lte: Optional[float] = None,
label_labeler_in: Optional[ListOrTuple[str]] = None,
label_labeler_not_in: Optional[ListOrTuple[str]] = None,
label_reviewer_in: Optional[ListOrTuple[str]] = None,
label_reviewer_not_in: Optional[ListOrTuple[str]] = None,
assignee_in: Optional[ListOrTuple[str]] = None,
assignee_not_in: Optional[ListOrTuple[str]] = None,
label_consensus_mark_gte: Optional[float] = None,
label_consensus_mark_lte: Optional[float] = None,
label_created_at_gte: Optional[str] = None,
label_created_at_lte: Optional[str] = None,
label_honeypot_mark_gte: Optional[float] = None,
label_honeypot_mark_lte: Optional[float] = None,
issue_type: Optional[IssueType] = None,
issue_status: Optional[IssueStatus] = None,
external_id_strictly_in: Optional[list[str]] = None,
external_id_in: Optional[list[str]] = None,
label_output_format: Literal["dict", "parsed_label"] = "dict",
skipped: Optional[bool] = None,
status_in: Optional[list[AssetStatus]] = None,
step_name_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_in: Optional[list[str]] = None,
step_name_not_in: Optional[list[str]] = None,
step_status_in: Optional[list[StatusInStep]] = None,
step_status_not_in: Optional[list[StatusInStep]] = None,
group_name_in: Optional[list[str]] = None,
group_name_not_in: Optional[list[str]] = None,
*,
as_generator: Literal[True],
step_id_in: Optional[list[str]] = None,
step_id_not_in: Optional[list[str]] = None,
step_id_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_id_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
) -> Generator[dict, None, None]:
...
@overload
def assets(
self,
project_id: str,
asset_id: Optional[str] = None,
skip: int = 0,
fields: Optional[ListOrTuple[str]] = None,
asset_id_in: Optional[list[str]] = None,
asset_id_not_in: Optional[list[str]] = None,
disable_tqdm: Optional[bool] = None,
first: Optional[int] = None,
format: Optional[str] = None,
label_author_in: Optional[list[str]] = None,
label_created_at: Optional[str] = None,
label_type_in: Optional[list[LabelType]] = None,
metadata_where: Optional[dict] = None,
updated_at_gte: Optional[str] = None,
updated_at_lte: Optional[str] = None,
label_category_search: Optional[str] = None,
download_media: bool = False,
local_media_dir: Optional[str] = None,
created_at_gte: Optional[str] = None,
created_at_lte: Optional[str] = None,
honeypot_mark_gte: Optional[float] = None,
honeypot_mark_lte: Optional[float] = None,
consensus_mark_gte: Optional[float] = None,
consensus_mark_lte: Optional[float] = None,
inference_mark_gte: Optional[float] = None,
inference_mark_lte: Optional[float] = None,
label_labeler_in: Optional[ListOrTuple[str]] = None,
label_labeler_not_in: Optional[ListOrTuple[str]] = None,
label_reviewer_in: Optional[ListOrTuple[str]] = None,
label_reviewer_not_in: Optional[ListOrTuple[str]] = None,
assignee_in: Optional[ListOrTuple[str]] = None,
assignee_not_in: Optional[ListOrTuple[str]] = None,
label_consensus_mark_gte: Optional[float] = None,
label_consensus_mark_lte: Optional[float] = None,
label_created_at_gte: Optional[str] = None,
label_created_at_lte: Optional[str] = None,
label_honeypot_mark_gte: Optional[float] = None,
label_honeypot_mark_lte: Optional[float] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
issue_status: Optional[IssueStatus] = None,
external_id_strictly_in: Optional[list[str]] = None,
external_id_in: Optional[list[str]] = None,
label_output_format: Literal["dict", "parsed_label"] = "dict",
skipped: Optional[bool] = None,
status_in: Optional[list[AssetStatus]] = None,
step_name_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_in: Optional[list[str]] = None,
step_name_not_in: Optional[list[str]] = None,
step_status_in: Optional[list[StatusInStep]] = None,
step_status_not_in: Optional[list[StatusInStep]] = None,
group_name_in: Optional[list[str]] = None,
group_name_not_in: Optional[list[str]] = None,
*,
as_generator: Literal[False] = False,
step_id_in: Optional[list[str]] = None,
step_id_not_in: Optional[list[str]] = None,
step_id_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_id_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
) -> list[dict]:
...
# pylint: disable=too-many-branches
@typechecked
def assets(
self,
project_id: str,
asset_id: Optional[str] = None,
skip: int = 0,
fields: Optional[ListOrTuple[str]] = None,
asset_id_in: Optional[list[str]] = None,
asset_id_not_in: Optional[list[str]] = None,
disable_tqdm: Optional[bool] = None,
first: Optional[int] = None,
format: Optional[str] = None,
label_author_in: Optional[list[str]] = None,
label_created_at: Optional[str] = None,
label_type_in: Optional[list[LabelType]] = None,
metadata_where: Optional[dict] = None,
updated_at_gte: Optional[str] = None,
updated_at_lte: Optional[str] = None,
label_category_search: Optional[str] = None,
download_media: bool = False,
local_media_dir: Optional[str] = None,
created_at_gte: Optional[str] = None,
created_at_lte: Optional[str] = None,
honeypot_mark_gte: Optional[float] = None,
honeypot_mark_lte: Optional[float] = None,
consensus_mark_gte: Optional[float] = None,
consensus_mark_lte: Optional[float] = None,
inference_mark_gte: Optional[float] = None,
inference_mark_lte: Optional[float] = None,
label_labeler_in: Optional[ListOrTuple[str]] = None,
label_labeler_not_in: Optional[ListOrTuple[str]] = None,
label_reviewer_in: Optional[ListOrTuple[str]] = None,
label_reviewer_not_in: Optional[ListOrTuple[str]] = None,
assignee_in: Optional[ListOrTuple[str]] = None,
assignee_not_in: Optional[ListOrTuple[str]] = None,
label_consensus_mark_gte: Optional[float] = None,
label_consensus_mark_lte: Optional[float] = None,
label_created_at_gte: Optional[str] = None,
label_created_at_lte: Optional[str] = None,
label_honeypot_mark_gte: Optional[float] = None,
label_honeypot_mark_lte: Optional[float] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
issue_status: Optional[Literal["CANCELLED", "OPEN", "SOLVED"]] = None,
external_id_strictly_in: Optional[list[str]] = None,
external_id_in: Optional[list[str]] = None,
label_output_format: Literal["dict", "parsed_label"] = "dict",
skipped: Optional[bool] = None,
status_in: Optional[list[AssetStatus]] = None,
step_name_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_in: Optional[list[str]] = None,
step_name_not_in: Optional[list[str]] = None,
step_status_in: Optional[list[StatusInStep]] = None,
step_status_not_in: Optional[list[StatusInStep]] = None,
group_name_in: Optional[list[str]] = None,
group_name_not_in: Optional[list[str]] = None,
*,
as_generator: bool = False,
step_id_in: Optional[list[str]] = None,
step_id_not_in: Optional[list[str]] = None,
step_id_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_id_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
) -> Union[Iterable[dict], "pd.DataFrame"]:
# pylint: disable=line-too-long
"""Get an asset list, an asset generator or a pandas DataFrame that match a set of constraints.
Args:
project_id: Identifier of the project.
asset_id: Identifier of the asset to retrieve.
asset_id_in: A list of the IDs of the assets to retrieve.
asset_id_not_in: A list of the IDs of the assets to exclude.
skip: Number of assets to skip (they are ordered by their date of creation, first to last).
fields: All the fields to request among the possible fields for the assets.
See [the documentation](https://api-docs.kili-technology.com/types/objects/asset) for all possible fields.
`resolution` is empty on a `GEOSPATIAL` asset: its dimensions are per layer,
carried by `geospatialExportMetadata` with the CRS the layer is labeled in.
first: Maximum number of assets to return.
metadata_where: Filters by the values of the metadata of the asset.
label_type_in: Returned assets should have a label whose type belongs to that list, if given.
label_author_in: Returned assets should have a label whose author belongs to that list, if given. An author can be designated by the first name, the last name, or the first name + last name.
label_created_at: Returned assets should have a label whose creation date is equal to this date.
updated_at_gte: Returned assets should have an update date that is greater or equal to this date. The update date represents the last time a modification has been done at the asset level.
updated_at_lte: Returned assets should have an update date that is lower or equal to this date. The update date represents the last time a modification has been done at the asset level.
format: If equal to 'pandas', returns a pandas DataFrame
disable_tqdm: If `True`, the progress bar will be disabled
as_generator: If `True`, a generator on the assets is returned.
label_category_search: Returned assets should have a label that follows this category search query.
download_media: Tell is the media have to be downloaded or not.
local_media_dir: Directory where the media are downloaded if `download_media` is True.
created_at_gte: Returned assets should have their import date greater or equal to this date.
created_at_lte: Returned assets should have their import date lower or equal to this date.
honeypot_mark_lte: Maximum amount of honeypot for the asset.
honeypot_mark_gte: Minimum amount of honeypot for the asset.
consensus_mark_lte: Maximum amount of consensus for the asset.
consensus_mark_gte: Minimum amount of consensus for the asset.
inference_mark_gte: Minimum amount of human/model IoU for the asset.
inference_mark_lte: Maximum amount of human/model IoU for the asset.
label_labeler_in: Returned assets should have a label whose labeler belongs to that list, if given.
label_labeler_not_in: Returned assets should have a label whose labeler does not belong to that list, if given.
label_reviewer_in: Returned assets should have a label whose reviewer belongs to that list, if given.
label_reviewer_not_in: Returned assets should have a label whose reviewer does not belong to that list, if given.
assignee_in: Returned assets should have an assigned user that belongs to that list, if given.
assignee_not_in: Returned assets should have an assigned user that does not belong to that list, if given.
label_consensus_mark_gte: Returned assets should have a label whose consensus is greater or equal to this number.
label_consensus_mark_lte: Returned assets should have a label whose consensus is lower or equal to this number.
label_created_at_lte: Returned assets should have a label whose creation date is lower or equal to this date.
label_created_at_gte: Returned assets should have a label whose creation date is greater or equal to this date.
label_honeypot_mark_gte: Returned assets should have a label whose honeypot is greater or equal to this number.
label_honeypot_mark_lte: Returned assets should have a label whose honeypot is lower or equal to this number.
issue_type: Returned assets should have issues of type `QUESTION` or `ISSUE`.
issue_status: Returned assets should have issues of status `CANCELLED`, `OPEN` or `SOLVED`.
external_id_strictly_in: Returned assets should have external ids that match exactly the ones in the list.
external_id_in: Returned assets should have external ids that partially match the ones in the list.
For example, with `external_id_in=['abc']`, any asset with an external id containing `'abc'` will be returned.
label_output_format: If `parsed_label`, the labels in the assets will be parsed. More information on parsed labels in the [documentation](https://python-sdk-docs.kili-technology.com/latest/sdk/tutorials/label_parsing/).
skipped: Returned assets should be skipped
Only applicable if the project uses the legacy workflow.
status_in: Returned assets should have a status that belongs to that list, if given.
Possible choices: `TODO`, `ONGOING`, `LABELED`, `TO_REVIEW` or `REVIEWED`.
Only applicable if the project uses the legacy workflow.
step_name_and_status_in: Returned assets match at least one of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_and_status_not_in: Returned assets do not match any of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_in: Returned assets are in the step whose name belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_not_in: Returned assets are in the step whose name does not belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_id_in: Returned assets are in the step whose id belong to that list, if given.
Exclusive with `step_name_in`. Only applicable if the project uses the multi-step or multi-group workflow.
step_id_not_in: Returned assets are in the step whose id does not belong to that list,
if given. Exclusive with `step_name_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_in: Returned assets match at least one of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_not_in: Returned assets do not match any of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_status_in: Returned assets have the status in their step that belongs to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
step_status_not_in: Returned assets have the status in their step that does not belong to that list, if given.
Possible choices: `TO_DO`, `DOING`, `IN_PROGRESS`, `PARTIALLY_DONE`, `REWORK`, `REDO`, `DONE`, `SKIPPED` .
Only applicable if the project uses the multi-step or multi-group workflow. Note that `DOING` and `REDO` are deprecated, use `IN_PROGRESS` and `REWORK` instead.
group_name_in: Returned assets belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
group_name_not_in: Returned assets do not belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
!!! info "Dates format"
Date strings should have format: "YYYY-MM-DD"
!!! info "Filtering by label properties"
When the assets are filtered by label properties using any of `label_*` filter arguments, as soon as **one**
label matches **all** the label property criteria, the asset is kept and returned by the method. If any of the
`labels.*` or `latestLabel.*` subfields are queried, **all** the labels of the kept assets are returned together
with the assets (and not only the ones matching the criteria)
Returns:
An asset list, an asset generator or a pandas DataFrame that match a set of constraints.
Example:
```
# returns the assets list of the project
>>> kili.assets(project_id)
>>> kili.assets(project_id, asset_id=asset_id)
# returns a generator of the project assets
>>> kili.assets(project_id, as_generator=True)
```
!!! example "How to filter based on Metadata"
- `metadata_where = {key1: "value1"}` to filter on assets whose metadata
have key "key1" with value "value1"
- `metadata_where = {key1: ["value1", "value2"]}` to filter on assets whose metadata
have key "key1" with value "value1" or value "value2
- `metadata_where = {key2: [2, 10]}` to filter on assets whose metadata
have key "key2" with a value between 2 and 10.
!!! example "How to filter based on label categories"
The search query is composed of logical expressions following this format:
[job_name].[category_name].count [comparaison_operator] [value]
where:
- `[job_name]` is the name of the job in the interface
- `[category_name]` is the name of the category in the interface for this job
- `[comparaison_operator]` can be one of: [`==`, `>=`, `<=`, `<`, `>`]
- `[value]` is an integer that represents the count of such objects of the given category in the label
These operations can be separated by OR and AND operators:
```python
label_category_search = `JOB_CLASSIF.CATEGORY_A.count > 0`
label_category_search = `JOB_CLASSIF.CATEGORY_A.count > 0 OR JOB_NER.CATEGORY_B.count > 0`
label_category_search = `(JOB_CLASSIF.CATEGORY_A.count == 1 OR JOB_NER.CATEGORY_B.count > 0) AND JOB_BBOX.CATEGORY_C.count > 10`
```
"""
if format == "pandas" and as_generator:
raise ValueError(
'Argument values as_generator==True and format=="pandas" are not compatible.'
)
if (step_status_in is not None and "DOING" in step_status_in) or (
step_status_not_in is not None and "DOING" in step_status_not_in
):
warnings.warn(
"Step status 'DOING' is deprecated, use 'IN_PROGRESS' instead",
DeprecationWarning,
stacklevel=1,
)
if (step_status_in is not None and "REDO" in step_status_in) or (
step_status_not_in is not None and "REDO" in step_status_not_in
):
warnings.warn(
"Step status 'REDO' is deprecated, use 'REWORK' instead",
DeprecationWarning,
stacklevel=1,
)
disable_tqdm = disable_tqdm_if_as_generator(as_generator, disable_tqdm)
project_use_cases = ProjectUseCases(self.kili_api_gateway)
project_steps, project_workflow_version = project_use_cases.get_project_steps_and_version(
project_id
)
if fields is None:
fields = get_asset_default_fields(project_workflow_version=project_workflow_version)
elif project_workflow_version == "V1":
for invalid_field in filter(lambda f: f.startswith("currentStep."), fields):
warnings.warn(
f"Field {invalid_field} requested : request 'status' field instead for this project",
stacklevel=1,
)
elif "status" in fields:
warnings.warn(
"Field status requested : request 'currentStep.name' and 'currentStep.status' fields instead for this project",
stacklevel=1,
)
has_step_or_status_filters = (
step_id_in is not None
or step_id_not_in is not None
or step_id_and_status_in is not None
or step_id_and_status_not_in is not None
or step_name_in is not None
or step_name_not_in is not None
or step_name_and_status_in is not None
or step_name_and_status_not_in is not None
or step_status_in is not None
or step_status_not_in is not None
or status_in is not None
or skipped is not None
or group_name_in is not None
or group_name_not_in is not None
)
if has_step_or_status_filters:
check_asset_workflow_arguments(
project_workflow_version=project_workflow_version,
asset_workflow_filters={
"skipped": skipped,
"status_in": status_in,
"step_name_in": step_name_in,
"has_step_id_filter": any(
f is not None
for f in (
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
)
),
"step_name_not_in": step_name_not_in,
"step_status_in": step_status_in,
"step_status_not_in": step_status_not_in,
"step_name_and_status_in": step_name_and_status_in,
"step_name_and_status_not_in": step_name_and_status_not_in,
"group_name_in": group_name_in,
"group_name_not_in": group_name_not_in,
},
)
if project_workflow_version in ("V2", "V3"):
(
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
) = resolve_step_filters(
project_steps,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
step_name_in=step_name_in,
step_name_not_in=step_name_not_in,
step_name_and_status_in=step_name_and_status_in,
step_name_and_status_not_in=step_name_and_status_not_in,
)
# Resolve disable_tqdm: function parameter > client global setting > function default
disable_tqdm = resolve_disable_tqdm(disable_tqdm, getattr(self, "disable_tqdm", None))
asset_use_cases = AssetUseCases(self.kili_api_gateway)
filters = AssetFilters(
project_id=ProjectId(project_id),
asset_id=AssetId(asset_id) if asset_id else None,
asset_id_in=cast(list[AssetId], asset_id_in) if asset_id_in else None,
asset_id_not_in=cast(list[AssetId], asset_id_not_in) if asset_id_not_in else None,
consensus_mark_gte=consensus_mark_gte,
consensus_mark_lte=consensus_mark_lte,
external_id_strictly_in=(
cast(list[AssetExternalId], external_id_strictly_in)
if external_id_strictly_in
else None
),
external_id_in=cast(list[AssetExternalId], external_id_in) if external_id_in else None,
honeypot_mark_gte=honeypot_mark_gte,
honeypot_mark_lte=honeypot_mark_lte,
inference_mark_gte=inference_mark_gte,
inference_mark_lte=inference_mark_lte,
label_author_in=label_author_in,
label_consensus_mark_gte=label_consensus_mark_gte,
label_consensus_mark_lte=label_consensus_mark_lte,
label_created_at=label_created_at,
label_created_at_gte=label_created_at_gte,
label_created_at_lte=label_created_at_lte,
label_honeypot_mark_gte=label_honeypot_mark_gte,
label_honeypot_mark_lte=label_honeypot_mark_lte,
label_type_in=label_type_in,
metadata_where=metadata_where,
skipped=skipped,
status_in=status_in,
updated_at_gte=updated_at_gte,
updated_at_lte=updated_at_lte,
label_category_search=label_category_search,
created_at_gte=created_at_gte,
created_at_lte=created_at_lte,
label_labeler_in=label_labeler_in,
label_labeler_not_in=label_labeler_not_in,
label_reviewer_in=label_reviewer_in,
label_reviewer_not_in=label_reviewer_not_in,
assignee_in=assignee_in,
assignee_not_in=assignee_not_in,
issue_status=issue_status,
issue_type=issue_type,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_status_in=step_status_in,
step_status_not_in=step_status_not_in,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
group_name_in=group_name_in if group_name_in else None,
group_name_not_in=group_name_not_in if group_name_not_in else None,
)
assets_gen = asset_use_cases.list_assets(
filters,
fields,
download_media=download_media,
local_media_dir=local_media_dir,
label_output_format=label_output_format,
options=QueryOptions(disable_tqdm=disable_tqdm, first=first, skip=skip),
)
if format == "pandas":
try:
import pandas as pd # pylint: disable=import-outside-toplevel
except ImportError as e:
raise ImportError("Install `pip install kili[pandas]` for format='pandas'.") from e
return pd.DataFrame(list(assets_gen))
if as_generator:
return assets_gen
return list(assets_gen)
# pylint: disable=too-many-arguments,too-many-locals
@typechecked
def count_assets(
self,
project_id: str,
asset_id: Optional[str] = None,
asset_id_in: Optional[list[str]] = None,
asset_id_not_in: Optional[list[str]] = None,
metadata_where: Optional[dict] = None,
status_in: Optional[list[AssetStatus]] = None,
label_type_in: Optional[list[LabelType]] = None,
label_author_in: Optional[list[str]] = None,
label_created_at: Optional[str] = None,
skipped: Optional[bool] = None,
updated_at_gte: Optional[str] = None,
updated_at_lte: Optional[str] = None,
label_category_search: Optional[str] = None,
created_at_gte: Optional[str] = None,
created_at_lte: Optional[str] = None,
honeypot_mark_gte: Optional[float] = None,
honeypot_mark_lte: Optional[float] = None,
consensus_mark_gte: Optional[float] = None,
consensus_mark_lte: Optional[float] = None,
inference_mark_gte: Optional[float] = None,
inference_mark_lte: Optional[float] = None,
label_labeler_in: Optional[ListOrTuple[str]] = None,
label_labeler_not_in: Optional[ListOrTuple[str]] = None,
label_reviewer_in: Optional[ListOrTuple[str]] = None,
label_reviewer_not_in: Optional[ListOrTuple[str]] = None,
assignee_in: Optional[ListOrTuple[str]] = None,
assignee_not_in: Optional[ListOrTuple[str]] = None,
label_consensus_mark_gte: Optional[float] = None,
label_consensus_mark_lte: Optional[float] = None,
label_created_at_gte: Optional[str] = None,
label_created_at_lte: Optional[str] = None,
label_honeypot_mark_gte: Optional[float] = None,
label_honeypot_mark_lte: Optional[float] = None,
issue_type: Optional[IssueType] = None,
issue_status: Optional[IssueStatus] = None,
external_id_strictly_in: Optional[list[str]] = None,
external_id_in: Optional[list[str]] = None,
step_name_in: Optional[list[str]] = None,
step_name_not_in: Optional[list[str]] = None,
step_status_in: Optional[list[StatusInStep]] = None,
step_status_not_in: Optional[list[StatusInStep]] = None,
step_name_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
group_name_in: Optional[list[str]] = None,
group_name_not_in: Optional[list[str]] = None,
step_id_in: Optional[list[str]] = None,
step_id_not_in: Optional[list[str]] = None,
step_id_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_id_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
) -> int:
# pylint: disable=line-too-long
"""Count and return the number of assets with the given constraints.
Parameters beginning with 'label_' apply to labels, others apply to assets.
Args:
project_id: Identifier of the project
asset_id: The unique id of the asset to retrieve.
asset_id_in: A list of the ids of the assets to retrieve.
asset_id_not_in: A list of the ids of the assets to exclude.
metadata_where: Filters by the values of the metadata of the asset.
status_in: Returned assets should have a status that belongs to that list, if given. Possible choices: `TODO`, `ONGOING`, `LABELED`, `TO_REVIEW` or `REVIEWED`.
label_type_in: Returned assets should have a label whose type belongs to that list, if given.
label_author_in: Returned assets should have a label whose author belongs to that list, if given. An author can be designated by the first name, the last name, or the first name + last name.
label_created_at: Returned assets should have a label whose creation date is equal to this date.
skipped: Returned assets should be skipped.
updated_at_gte: Returned assets should have an update date that is greated or equal to this date. The update date represents the last time a modification has been done at the asset level.
updated_at_lte: Returned assets should have an update date that is lower or equal to this date. The update date represents the last time a modification has been done at the asset level.
label_category_search: Returned assets should have a label that follows this category search query.
created_at_gte: Returned assets should have their import date greater or equal to this date.
created_at_lte: Returned assets should have their import date lower or equal to this date.
honeypot_mark_lte: Maximum amount of honeypot for the asset.
honeypot_mark_gte: Minimum amount of honeypot for the asset.
consensus_mark_lte: Maximum amount of consensus for the asset.
consensus_mark_gte: Minimum amount of consensus for the asset.
inference_mark_gte: Minimum amount of human/model IoU for the asset.
inference_mark_lte: Maximum amount of human/model IoU for the asset.
label_labeler_in: Returned assets should have a label whose labeler belongs to that list, if given.
label_labeler_not_in: Returned assets should have a label whose labeler does not belong to that list, if given.
label_reviewer_in: Returned assets should have a label whose reviewer belongs to that list, if given.
label_reviewer_not_in: Returned assets should have a label whose reviewer does not belong to that list, if given.
assignee_in: Returned assets should have an assigned user that belongs to that list, if given.
assignee_not_in: Returned assets should have an assigned user that does not belong to that list, if given.
label_consensus_mark_gte: Returned assets should have a label whose consensus is greater or equal to this number.
label_consensus_mark_lte: Returned assets should have a label whose consensus is lower or equal to this number.
label_created_at_lte: Returned assets should have a label whose creation date is lower or equal to this date.
label_created_at_gte: Returned assets should have a label whose creation date is greater or equal to this date.
label_honeypot_mark_gte: Returned assets should have a label whose honeypot is greater or equal to this number.
label_honeypot_mark_lte: Returned assets should have a label whose honeypot is lower or equal to this number.
issue_type: Returned assets should have issues of type `QUESTION` or `ISSUE`.
issue_status: Returned assets should have issues of status `OPEN` or `SOLVED`.
external_id_strictly_in: Returned assets should have external ids that match exactly the ones in the list.
external_id_in: Returned assets should have external ids that partially match the ones in the list.
For example, with `external_id_in=['abc']`, any asset with an external id containing `'abc'` will be returned.
step_name_in: Returned assets are in a step whose name belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_not_in: Returned assets are in a step whose name does not belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_id_in: Returned assets are in the step whose id belong to that list, if given.
Exclusive with `step_name_in`. Only applicable if the project uses the multi-step or multi-group workflow.
step_id_not_in: Returned assets are in the step whose id does not belong to that list,
if given. Exclusive with `step_name_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_in: Returned assets match at least one of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_not_in: Returned assets do not match any of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_status_in: Returned assets have the status of their step that belongs to that list, if given.
Possible choices: `TO_DO`, `DOING`, `IN_PROGRESS`, `PARTIALLY_DONE`, `REWORK`, `REDO`, `DONE`, `SKIPPED`.
Only applicable if the project uses the multi-step or multi-group workflow. Note that `DOING` and `REDO` are deprecated, use `IN_PROGRESS` and `REWORK` instead.
step_status_not_in: Returned assets have the status of their step that does not belong to that list, if given.
Possible choices: `TO_DO`, `DOING`, `IN_PROGRESS`, `PARTIALLY_DONE`, `REWORK`, `REDO`, `DONE`, `SKIPPED`.
Only applicable if the project uses the multi-step or multi-group workflow. Note that `DOING` and `REDO` are deprecated, use `IN_PROGRESS` and `REWORK` instead.
step_name_and_status_in: Returned assets match at least one of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_and_status_not_in: Returned assets do not match any of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
group_name_in: Returned assets belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
group_name_not_in: Returned assets do not belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
!!! info "Dates format"
Date strings should have format: "YYYY-MM-DD"
Returns:
The number of assets that match the given constraints.
Examples:
>>> kili.count_assets(project_id=project_id)
250
>>> kili.count_assets(asset_id=asset_id)
1
!!! example "How to filter based on Metadata"
- `metadata_where = {key1: "value1"}` to filter on assets whose metadata
have key "key1" with value "value1"
- `metadata_where = {key1: ["value1", "value2"]}` to filter on assets whose metadata
have key "key1" with value "value1" or value "value2
- `metadata_where = {key2: [2, 10]}` to filter on assets whose metadata
have key "key2" with a value between 2 and 10.
"""
if (step_status_in is not None and "DOING" in step_status_in) or (
step_status_not_in is not None and "DOING" in step_status_not_in
):
warnings.warn(
"Step status 'DOING' is deprecated, use 'IN_PROGRESS' instead",
DeprecationWarning,
stacklevel=1,
)
if (step_status_in is not None and "REDO" in step_status_in) or (
step_status_not_in is not None and "REDO" in step_status_not_in
):
warnings.warn(
"Step status 'REDO' is deprecated, use 'REWORK' instead",
DeprecationWarning,
stacklevel=1,
)
has_step_or_status_filters = (
step_id_in is not None
or step_id_not_in is not None
or step_id_and_status_in is not None
or step_id_and_status_not_in is not None
or step_name_in is not None
or step_name_not_in is not None
or step_name_and_status_in is not None
or step_name_and_status_not_in is not None
or status_in is not None
or step_status_in is not None
or step_status_not_in is not None
or group_name_in is not None
or group_name_not_in is not None
)
if has_step_or_status_filters:
project_use_cases = ProjectUseCases(self.kili_api_gateway)
(
project_steps,
project_workflow_version,
) = project_use_cases.get_project_steps_and_version(project_id)
check_asset_workflow_arguments(
project_workflow_version=project_workflow_version,
asset_workflow_filters={
"skipped": skipped,
"step_name_in": step_name_in,
"has_step_id_filter": any(
f is not None
for f in (
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
)
),
"step_name_and_status_in": step_name_and_status_in,
"step_name_and_status_not_in": step_name_and_status_not_in,
"step_name_not_in": step_name_not_in,
"step_status_in": step_status_in,
"step_status_not_in": step_status_not_in,
"status_in": status_in,
"group_name_in": group_name_in,
"group_name_not_in": group_name_not_in,
},
)
if project_workflow_version in ("V2", "V3"):
(
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
) = resolve_step_filters(
project_steps,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
step_name_in=step_name_in,
step_name_not_in=step_name_not_in,
step_name_and_status_in=step_name_and_status_in,
step_name_and_status_not_in=step_name_and_status_not_in,
)
filters = AssetFilters(
project_id=ProjectId(project_id),
asset_id=AssetId(asset_id) if asset_id else None,
asset_id_in=cast(list[AssetId], asset_id_in) if asset_id_in else None,
asset_id_not_in=cast(list[AssetId], asset_id_not_in) if asset_id_not_in else None,
consensus_mark_gte=consensus_mark_gte,
consensus_mark_lte=consensus_mark_lte,
external_id_strictly_in=(
cast(list[AssetExternalId], external_id_strictly_in)
if external_id_strictly_in
else None
),
external_id_in=cast(list[AssetExternalId], external_id_in) if external_id_in else None,
honeypot_mark_gte=honeypot_mark_gte,
honeypot_mark_lte=honeypot_mark_lte,
inference_mark_gte=inference_mark_gte,
inference_mark_lte=inference_mark_lte,
label_author_in=label_author_in,
label_labeler_in=label_labeler_in,
label_labeler_not_in=label_labeler_not_in,
label_reviewer_in=label_reviewer_in,
label_reviewer_not_in=label_reviewer_not_in,
assignee_in=assignee_in,
assignee_not_in=assignee_not_in,
label_consensus_mark_gte=label_consensus_mark_gte,
label_consensus_mark_lte=label_consensus_mark_lte,
label_created_at=label_created_at,
label_created_at_gte=label_created_at_gte,
label_created_at_lte=label_created_at_lte,
label_honeypot_mark_gte=label_honeypot_mark_gte,
label_honeypot_mark_lte=label_honeypot_mark_lte,
label_type_in=label_type_in,
metadata_where=metadata_where,
skipped=skipped,
status_in=status_in,
updated_at_gte=updated_at_gte,
updated_at_lte=updated_at_lte,
label_category_search=label_category_search,
created_at_gte=created_at_gte,
created_at_lte=created_at_lte,
issue_status=issue_status,
issue_type=issue_type,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_status_in=step_status_in,
step_status_not_in=step_status_not_in,
group_name_in=group_name_in if group_name_in else None,
group_name_not_in=group_name_not_in if group_name_not_in else None,
)
asset_use_cases = AssetUseCases(self.kili_api_gateway)
return asset_use_cases.count_assets(filters)
@typechecked
def update_asset_consensus(
self,
project_id: str,
is_consensus: bool,
asset_id: Optional[str] = None,
external_id: Optional[str] = None,
) -> bool:
"""Activate or deactivate consensus on an asset.
This method is not compatible with projects using the legacy workflow. On those projects,
use `kili.update_properties_in_assets()` with `is_used_for_consensus_array` instead.
Args:
project_id: The project ID.
is_consensus: Whether to activate (True) or deactivate (False) consensus on the asset.
asset_id: The internal asset ID to modify. Either asset_id or external_id must be provided.
external_id: The external ID of the asset to modify. Either asset_id or external_id must be provided.
Returns:
The consensus value that was set (True if consensus was activated, False if deactivated).
Raises:
ValueError: If neither asset_id nor external_id is provided.
GraphQLError: If a server-side precondition is not met. The server accepts the
call only on multi-step or multi-group workflow projects, while the asset sits on
a labeling (DEFAULT) step whose status is still TO_DO, when consensus is enabled
on that step, and when the caller is an admin or a team manager. Note that the TO_DO
window closes as soon as any labeler starts working on the asset (their first
autosave, not their submission), so the real precondition is that no labeler
has opened and started the asset yet.
Examples:
>>> # Activate consensus on an asset using asset_id
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=True,
... asset_id="ckg22d81r0jrg0885unmuswj8"
... )
>>> # result is True
>>> # Activate consensus on an asset using external_id
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=True,
... external_id="my_asset_001"
... )
>>> # result is True
>>> # Deactivate consensus on an asset
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=False,
... asset_id="ckg22d81r0jrg0885unmuswj8"
... )
>>> # result is False
"""
if asset_id is None and external_id is None:
raise ValueError(
"At least one of asset_id or external_id must be provided to update_asset_consensus"
)
return self.kili_api_gateway.update_asset_consensus(
project_id=project_id,
is_consensus=is_consensus,
asset_id=asset_id,
external_id=external_id,
)
assets(self, project_id, asset_id=None, skip=0, fields=None, asset_id_in=None, asset_id_not_in=None, disable_tqdm=None, first=None, format=None, label_author_in=None, label_created_at=None, label_type_in=None, metadata_where=None, updated_at_gte=None, updated_at_lte=None, label_category_search=None, download_media=False, local_media_dir=None, created_at_gte=None, created_at_lte=None, honeypot_mark_gte=None, honeypot_mark_lte=None, consensus_mark_gte=None, consensus_mark_lte=None, inference_mark_gte=None, inference_mark_lte=None, label_labeler_in=None, label_labeler_not_in=None, label_reviewer_in=None, label_reviewer_not_in=None, assignee_in=None, assignee_not_in=None, label_consensus_mark_gte=None, label_consensus_mark_lte=None, label_created_at_gte=None, label_created_at_lte=None, label_honeypot_mark_gte=None, label_honeypot_mark_lte=None, issue_type=None, issue_status=None, external_id_strictly_in=None, external_id_in=None, label_output_format='dict', skipped=None, status_in=None, step_name_and_status_in=None, step_name_and_status_not_in=None, step_name_in=None, step_name_not_in=None, step_status_in=None, step_status_not_in=None, group_name_in=None, group_name_not_in=None, *, as_generator=False, step_id_in=None, step_id_not_in=None, step_id_and_status_in=None, step_id_and_status_not_in=None)
Get an asset list, an asset generator or a pandas DataFrame that match a set of constraints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id |
str |
Identifier of the project. |
required |
asset_id |
Optional[str] |
Identifier of the asset to retrieve. |
None |
asset_id_in |
Optional[list[str]] |
A list of the IDs of the assets to retrieve. |
None |
asset_id_not_in |
Optional[list[str]] |
A list of the IDs of the assets to exclude. |
None |
skip |
int |
Number of assets to skip (they are ordered by their date of creation, first to last). |
0 |
fields |
Union[list[str], tuple[str, ...]] |
All the fields to request among the possible fields for the assets.
See the documentation for all possible fields.
|
None |
first |
Optional[int] |
Maximum number of assets to return. |
None |
metadata_where |
Optional[dict] |
Filters by the values of the metadata of the asset. |
None |
label_type_in |
Optional[list[Literal['AUTOSAVE', 'DEFAULT', 'INFERENCE', 'PREDICTION', 'REVIEW']]] |
Returned assets should have a label whose type belongs to that list, if given. |
None |
label_author_in |
Optional[list[str]] |
Returned assets should have a label whose author belongs to that list, if given. An author can be designated by the first name, the last name, or the first name + last name. |
None |
label_created_at |
Optional[str] |
Returned assets should have a label whose creation date is equal to this date. |
None |
updated_at_gte |
Optional[str] |
Returned assets should have an update date that is greater or equal to this date. The update date represents the last time a modification has been done at the asset level. |
None |
updated_at_lte |
Optional[str] |
Returned assets should have an update date that is lower or equal to this date. The update date represents the last time a modification has been done at the asset level. |
None |
format |
Optional[str] |
If equal to 'pandas', returns a pandas DataFrame |
None |
disable_tqdm |
Optional[bool] |
If |
None |
as_generator |
bool |
If |
False |
label_category_search |
Optional[str] |
Returned assets should have a label that follows this category search query. |
None |
download_media |
bool |
Tell is the media have to be downloaded or not. |
False |
local_media_dir |
Optional[str] |
Directory where the media are downloaded if |
None |
created_at_gte |
Optional[str] |
Returned assets should have their import date greater or equal to this date. |
None |
created_at_lte |
Optional[str] |
Returned assets should have their import date lower or equal to this date. |
None |
honeypot_mark_lte |
Optional[float] |
Maximum amount of honeypot for the asset. |
None |
honeypot_mark_gte |
Optional[float] |
Minimum amount of honeypot for the asset. |
None |
consensus_mark_lte |
Optional[float] |
Maximum amount of consensus for the asset. |
None |
consensus_mark_gte |
Optional[float] |
Minimum amount of consensus for the asset. |
None |
inference_mark_gte |
Optional[float] |
Minimum amount of human/model IoU for the asset. |
None |
inference_mark_lte |
Optional[float] |
Maximum amount of human/model IoU for the asset. |
None |
label_labeler_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose labeler belongs to that list, if given. |
None |
label_labeler_not_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose labeler does not belong to that list, if given. |
None |
label_reviewer_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose reviewer belongs to that list, if given. |
None |
label_reviewer_not_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose reviewer does not belong to that list, if given. |
None |
assignee_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have an assigned user that belongs to that list, if given. |
None |
assignee_not_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have an assigned user that does not belong to that list, if given. |
None |
label_consensus_mark_gte |
Optional[float] |
Returned assets should have a label whose consensus is greater or equal to this number. |
None |
label_consensus_mark_lte |
Optional[float] |
Returned assets should have a label whose consensus is lower or equal to this number. |
None |
label_created_at_lte |
Optional[str] |
Returned assets should have a label whose creation date is lower or equal to this date. |
None |
label_created_at_gte |
Optional[str] |
Returned assets should have a label whose creation date is greater or equal to this date. |
None |
label_honeypot_mark_gte |
Optional[float] |
Returned assets should have a label whose honeypot is greater or equal to this number. |
None |
label_honeypot_mark_lte |
Optional[float] |
Returned assets should have a label whose honeypot is lower or equal to this number. |
None |
issue_type |
Optional[Literal['ISSUE', 'QUESTION']] |
Returned assets should have issues of type |
None |
issue_status |
Optional[Literal['CANCELLED', 'OPEN', 'SOLVED']] |
Returned assets should have issues of status |
None |
external_id_strictly_in |
Optional[list[str]] |
Returned assets should have external ids that match exactly the ones in the list. |
None |
external_id_in |
Optional[list[str]] |
Returned assets should have external ids that partially match the ones in the list.
For example, with |
None |
label_output_format |
Literal['dict', 'parsed_label'] |
If |
'dict' |
skipped |
Optional[bool] |
Returned assets should be skipped Only applicable if the project uses the legacy workflow. |
None |
status_in |
Optional[list[Literal['TODO', 'ONGOING', 'LABELED', 'REVIEWED', 'TO_REVIEW']]] |
Returned assets should have a status that belongs to that list, if given.
Possible choices: |
None |
step_name_and_status_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets match at least one of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
step_name_and_status_not_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets do not match any of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
step_name_in |
Optional[list[str]] |
Returned assets are in the step whose name belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
step_name_not_in |
Optional[list[str]] |
Returned assets are in the step whose name does not belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
step_id_in |
Optional[list[str]] |
Returned assets are in the step whose id belong to that list, if given.
Exclusive with |
None |
step_id_not_in |
Optional[list[str]] |
Returned assets are in the step whose id does not belong to that list,
if given. Exclusive with |
None |
step_id_and_status_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets match at least one of the given
(step_id, step_status) pairs. Exclusive with |
None |
step_id_and_status_not_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets do not match any of the given
(step_id, step_status) pairs. Exclusive with |
None |
step_status_in |
Optional[list[Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]] |
Returned assets have the status in their step that belongs to that list, if given. Only applicable if the project uses the multi-step or multi-group workflow. |
None |
step_status_not_in |
Optional[list[Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]] |
Returned assets have the status in their step that does not belong to that list, if given.
Possible choices: |
None |
group_name_in |
Optional[list[str]] |
Returned assets belong to a workflow step group whose name is in the list, if given. Only applicable if the project uses the multi-group workflow. |
None |
group_name_not_in |
Optional[list[str]] |
Returned assets do not belong to a workflow step group whose name is in the list, if given. Only applicable if the project uses the multi-group workflow. |
None |
Dates format
Date strings should have format: "YYYY-MM-DD"
Filtering by label properties
When the assets are filtered by label properties using any of label_* filter arguments, as soon as one
label matches all the label property criteria, the asset is kept and returned by the method. If any of the
labels.* or latestLabel.* subfields are queried, all the labels of the kept assets are returned together
with the assets (and not only the ones matching the criteria)
Returns:
| Type | Description |
|---|---|
Union[collections.abc.Iterable[dict], pd.DataFrame] |
An asset list, an asset generator or a pandas DataFrame that match a set of constraints. |
Examples:
# returns the assets list of the project
>>> kili.assets(project_id)
>>> kili.assets(project_id, asset_id=asset_id)
# returns a generator of the project assets
>>> kili.assets(project_id, as_generator=True)
How to filter based on Metadata
metadata_where = {key1: "value1"}to filter on assets whose metadata have key "key1" with value "value1"metadata_where = {key1: ["value1", "value2"]}to filter on assets whose metadata have key "key1" with value "value1" or value "value2metadata_where = {key2: [2, 10]}to filter on assets whose metadata have key "key2" with a value between 2 and 10.
How to filter based on label categories
The search query is composed of logical expressions following this format:
[job_name].[category_name].count [comparaison_operator] [value]
where:
[job_name]is the name of the job in the interface[category_name]is the name of the category in the interface for this job[comparaison_operator]can be one of: [==,>=,<=,<,>][value]is an integer that represents the count of such objects of the given category in the label
These operations can be separated by OR and AND operators:
label_category_search = `JOB_CLASSIF.CATEGORY_A.count > 0`
label_category_search = `JOB_CLASSIF.CATEGORY_A.count > 0 OR JOB_NER.CATEGORY_B.count > 0`
label_category_search = `(JOB_CLASSIF.CATEGORY_A.count == 1 OR JOB_NER.CATEGORY_B.count > 0) AND JOB_BBOX.CATEGORY_C.count > 10`
Source code in kili/presentation/client/asset.py
def assets(
self,
project_id: str,
asset_id: Optional[str] = None,
skip: int = 0,
fields: Optional[ListOrTuple[str]] = None,
asset_id_in: Optional[list[str]] = None,
asset_id_not_in: Optional[list[str]] = None,
disable_tqdm: Optional[bool] = None,
first: Optional[int] = None,
format: Optional[str] = None,
label_author_in: Optional[list[str]] = None,
label_created_at: Optional[str] = None,
label_type_in: Optional[list[LabelType]] = None,
metadata_where: Optional[dict] = None,
updated_at_gte: Optional[str] = None,
updated_at_lte: Optional[str] = None,
label_category_search: Optional[str] = None,
download_media: bool = False,
local_media_dir: Optional[str] = None,
created_at_gte: Optional[str] = None,
created_at_lte: Optional[str] = None,
honeypot_mark_gte: Optional[float] = None,
honeypot_mark_lte: Optional[float] = None,
consensus_mark_gte: Optional[float] = None,
consensus_mark_lte: Optional[float] = None,
inference_mark_gte: Optional[float] = None,
inference_mark_lte: Optional[float] = None,
label_labeler_in: Optional[ListOrTuple[str]] = None,
label_labeler_not_in: Optional[ListOrTuple[str]] = None,
label_reviewer_in: Optional[ListOrTuple[str]] = None,
label_reviewer_not_in: Optional[ListOrTuple[str]] = None,
assignee_in: Optional[ListOrTuple[str]] = None,
assignee_not_in: Optional[ListOrTuple[str]] = None,
label_consensus_mark_gte: Optional[float] = None,
label_consensus_mark_lte: Optional[float] = None,
label_created_at_gte: Optional[str] = None,
label_created_at_lte: Optional[str] = None,
label_honeypot_mark_gte: Optional[float] = None,
label_honeypot_mark_lte: Optional[float] = None,
issue_type: Optional[Literal["QUESTION", "ISSUE"]] = None,
issue_status: Optional[Literal["CANCELLED", "OPEN", "SOLVED"]] = None,
external_id_strictly_in: Optional[list[str]] = None,
external_id_in: Optional[list[str]] = None,
label_output_format: Literal["dict", "parsed_label"] = "dict",
skipped: Optional[bool] = None,
status_in: Optional[list[AssetStatus]] = None,
step_name_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_in: Optional[list[str]] = None,
step_name_not_in: Optional[list[str]] = None,
step_status_in: Optional[list[StatusInStep]] = None,
step_status_not_in: Optional[list[StatusInStep]] = None,
group_name_in: Optional[list[str]] = None,
group_name_not_in: Optional[list[str]] = None,
*,
as_generator: bool = False,
step_id_in: Optional[list[str]] = None,
step_id_not_in: Optional[list[str]] = None,
step_id_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_id_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
) -> Union[Iterable[dict], "pd.DataFrame"]:
# pylint: disable=line-too-long
"""Get an asset list, an asset generator or a pandas DataFrame that match a set of constraints.
Args:
project_id: Identifier of the project.
asset_id: Identifier of the asset to retrieve.
asset_id_in: A list of the IDs of the assets to retrieve.
asset_id_not_in: A list of the IDs of the assets to exclude.
skip: Number of assets to skip (they are ordered by their date of creation, first to last).
fields: All the fields to request among the possible fields for the assets.
See [the documentation](https://api-docs.kili-technology.com/types/objects/asset) for all possible fields.
`resolution` is empty on a `GEOSPATIAL` asset: its dimensions are per layer,
carried by `geospatialExportMetadata` with the CRS the layer is labeled in.
first: Maximum number of assets to return.
metadata_where: Filters by the values of the metadata of the asset.
label_type_in: Returned assets should have a label whose type belongs to that list, if given.
label_author_in: Returned assets should have a label whose author belongs to that list, if given. An author can be designated by the first name, the last name, or the first name + last name.
label_created_at: Returned assets should have a label whose creation date is equal to this date.
updated_at_gte: Returned assets should have an update date that is greater or equal to this date. The update date represents the last time a modification has been done at the asset level.
updated_at_lte: Returned assets should have an update date that is lower or equal to this date. The update date represents the last time a modification has been done at the asset level.
format: If equal to 'pandas', returns a pandas DataFrame
disable_tqdm: If `True`, the progress bar will be disabled
as_generator: If `True`, a generator on the assets is returned.
label_category_search: Returned assets should have a label that follows this category search query.
download_media: Tell is the media have to be downloaded or not.
local_media_dir: Directory where the media are downloaded if `download_media` is True.
created_at_gte: Returned assets should have their import date greater or equal to this date.
created_at_lte: Returned assets should have their import date lower or equal to this date.
honeypot_mark_lte: Maximum amount of honeypot for the asset.
honeypot_mark_gte: Minimum amount of honeypot for the asset.
consensus_mark_lte: Maximum amount of consensus for the asset.
consensus_mark_gte: Minimum amount of consensus for the asset.
inference_mark_gte: Minimum amount of human/model IoU for the asset.
inference_mark_lte: Maximum amount of human/model IoU for the asset.
label_labeler_in: Returned assets should have a label whose labeler belongs to that list, if given.
label_labeler_not_in: Returned assets should have a label whose labeler does not belong to that list, if given.
label_reviewer_in: Returned assets should have a label whose reviewer belongs to that list, if given.
label_reviewer_not_in: Returned assets should have a label whose reviewer does not belong to that list, if given.
assignee_in: Returned assets should have an assigned user that belongs to that list, if given.
assignee_not_in: Returned assets should have an assigned user that does not belong to that list, if given.
label_consensus_mark_gte: Returned assets should have a label whose consensus is greater or equal to this number.
label_consensus_mark_lte: Returned assets should have a label whose consensus is lower or equal to this number.
label_created_at_lte: Returned assets should have a label whose creation date is lower or equal to this date.
label_created_at_gte: Returned assets should have a label whose creation date is greater or equal to this date.
label_honeypot_mark_gte: Returned assets should have a label whose honeypot is greater or equal to this number.
label_honeypot_mark_lte: Returned assets should have a label whose honeypot is lower or equal to this number.
issue_type: Returned assets should have issues of type `QUESTION` or `ISSUE`.
issue_status: Returned assets should have issues of status `CANCELLED`, `OPEN` or `SOLVED`.
external_id_strictly_in: Returned assets should have external ids that match exactly the ones in the list.
external_id_in: Returned assets should have external ids that partially match the ones in the list.
For example, with `external_id_in=['abc']`, any asset with an external id containing `'abc'` will be returned.
label_output_format: If `parsed_label`, the labels in the assets will be parsed. More information on parsed labels in the [documentation](https://python-sdk-docs.kili-technology.com/latest/sdk/tutorials/label_parsing/).
skipped: Returned assets should be skipped
Only applicable if the project uses the legacy workflow.
status_in: Returned assets should have a status that belongs to that list, if given.
Possible choices: `TODO`, `ONGOING`, `LABELED`, `TO_REVIEW` or `REVIEWED`.
Only applicable if the project uses the legacy workflow.
step_name_and_status_in: Returned assets match at least one of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_and_status_not_in: Returned assets do not match any of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_in: Returned assets are in the step whose name belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_not_in: Returned assets are in the step whose name does not belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_id_in: Returned assets are in the step whose id belong to that list, if given.
Exclusive with `step_name_in`. Only applicable if the project uses the multi-step or multi-group workflow.
step_id_not_in: Returned assets are in the step whose id does not belong to that list,
if given. Exclusive with `step_name_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_in: Returned assets match at least one of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_not_in: Returned assets do not match any of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_status_in: Returned assets have the status in their step that belongs to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
step_status_not_in: Returned assets have the status in their step that does not belong to that list, if given.
Possible choices: `TO_DO`, `DOING`, `IN_PROGRESS`, `PARTIALLY_DONE`, `REWORK`, `REDO`, `DONE`, `SKIPPED` .
Only applicable if the project uses the multi-step or multi-group workflow. Note that `DOING` and `REDO` are deprecated, use `IN_PROGRESS` and `REWORK` instead.
group_name_in: Returned assets belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
group_name_not_in: Returned assets do not belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
!!! info "Dates format"
Date strings should have format: "YYYY-MM-DD"
!!! info "Filtering by label properties"
When the assets are filtered by label properties using any of `label_*` filter arguments, as soon as **one**
label matches **all** the label property criteria, the asset is kept and returned by the method. If any of the
`labels.*` or `latestLabel.*` subfields are queried, **all** the labels of the kept assets are returned together
with the assets (and not only the ones matching the criteria)
Returns:
An asset list, an asset generator or a pandas DataFrame that match a set of constraints.
Example:
```
# returns the assets list of the project
>>> kili.assets(project_id)
>>> kili.assets(project_id, asset_id=asset_id)
# returns a generator of the project assets
>>> kili.assets(project_id, as_generator=True)
```
!!! example "How to filter based on Metadata"
- `metadata_where = {key1: "value1"}` to filter on assets whose metadata
have key "key1" with value "value1"
- `metadata_where = {key1: ["value1", "value2"]}` to filter on assets whose metadata
have key "key1" with value "value1" or value "value2
- `metadata_where = {key2: [2, 10]}` to filter on assets whose metadata
have key "key2" with a value between 2 and 10.
!!! example "How to filter based on label categories"
The search query is composed of logical expressions following this format:
[job_name].[category_name].count [comparaison_operator] [value]
where:
- `[job_name]` is the name of the job in the interface
- `[category_name]` is the name of the category in the interface for this job
- `[comparaison_operator]` can be one of: [`==`, `>=`, `<=`, `<`, `>`]
- `[value]` is an integer that represents the count of such objects of the given category in the label
These operations can be separated by OR and AND operators:
```python
label_category_search = `JOB_CLASSIF.CATEGORY_A.count > 0`
label_category_search = `JOB_CLASSIF.CATEGORY_A.count > 0 OR JOB_NER.CATEGORY_B.count > 0`
label_category_search = `(JOB_CLASSIF.CATEGORY_A.count == 1 OR JOB_NER.CATEGORY_B.count > 0) AND JOB_BBOX.CATEGORY_C.count > 10`
```
"""
if format == "pandas" and as_generator:
raise ValueError(
'Argument values as_generator==True and format=="pandas" are not compatible.'
)
if (step_status_in is not None and "DOING" in step_status_in) or (
step_status_not_in is not None and "DOING" in step_status_not_in
):
warnings.warn(
"Step status 'DOING' is deprecated, use 'IN_PROGRESS' instead",
DeprecationWarning,
stacklevel=1,
)
if (step_status_in is not None and "REDO" in step_status_in) or (
step_status_not_in is not None and "REDO" in step_status_not_in
):
warnings.warn(
"Step status 'REDO' is deprecated, use 'REWORK' instead",
DeprecationWarning,
stacklevel=1,
)
disable_tqdm = disable_tqdm_if_as_generator(as_generator, disable_tqdm)
project_use_cases = ProjectUseCases(self.kili_api_gateway)
project_steps, project_workflow_version = project_use_cases.get_project_steps_and_version(
project_id
)
if fields is None:
fields = get_asset_default_fields(project_workflow_version=project_workflow_version)
elif project_workflow_version == "V1":
for invalid_field in filter(lambda f: f.startswith("currentStep."), fields):
warnings.warn(
f"Field {invalid_field} requested : request 'status' field instead for this project",
stacklevel=1,
)
elif "status" in fields:
warnings.warn(
"Field status requested : request 'currentStep.name' and 'currentStep.status' fields instead for this project",
stacklevel=1,
)
has_step_or_status_filters = (
step_id_in is not None
or step_id_not_in is not None
or step_id_and_status_in is not None
or step_id_and_status_not_in is not None
or step_name_in is not None
or step_name_not_in is not None
or step_name_and_status_in is not None
or step_name_and_status_not_in is not None
or step_status_in is not None
or step_status_not_in is not None
or status_in is not None
or skipped is not None
or group_name_in is not None
or group_name_not_in is not None
)
if has_step_or_status_filters:
check_asset_workflow_arguments(
project_workflow_version=project_workflow_version,
asset_workflow_filters={
"skipped": skipped,
"status_in": status_in,
"step_name_in": step_name_in,
"has_step_id_filter": any(
f is not None
for f in (
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
)
),
"step_name_not_in": step_name_not_in,
"step_status_in": step_status_in,
"step_status_not_in": step_status_not_in,
"step_name_and_status_in": step_name_and_status_in,
"step_name_and_status_not_in": step_name_and_status_not_in,
"group_name_in": group_name_in,
"group_name_not_in": group_name_not_in,
},
)
if project_workflow_version in ("V2", "V3"):
(
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
) = resolve_step_filters(
project_steps,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
step_name_in=step_name_in,
step_name_not_in=step_name_not_in,
step_name_and_status_in=step_name_and_status_in,
step_name_and_status_not_in=step_name_and_status_not_in,
)
# Resolve disable_tqdm: function parameter > client global setting > function default
disable_tqdm = resolve_disable_tqdm(disable_tqdm, getattr(self, "disable_tqdm", None))
asset_use_cases = AssetUseCases(self.kili_api_gateway)
filters = AssetFilters(
project_id=ProjectId(project_id),
asset_id=AssetId(asset_id) if asset_id else None,
asset_id_in=cast(list[AssetId], asset_id_in) if asset_id_in else None,
asset_id_not_in=cast(list[AssetId], asset_id_not_in) if asset_id_not_in else None,
consensus_mark_gte=consensus_mark_gte,
consensus_mark_lte=consensus_mark_lte,
external_id_strictly_in=(
cast(list[AssetExternalId], external_id_strictly_in)
if external_id_strictly_in
else None
),
external_id_in=cast(list[AssetExternalId], external_id_in) if external_id_in else None,
honeypot_mark_gte=honeypot_mark_gte,
honeypot_mark_lte=honeypot_mark_lte,
inference_mark_gte=inference_mark_gte,
inference_mark_lte=inference_mark_lte,
label_author_in=label_author_in,
label_consensus_mark_gte=label_consensus_mark_gte,
label_consensus_mark_lte=label_consensus_mark_lte,
label_created_at=label_created_at,
label_created_at_gte=label_created_at_gte,
label_created_at_lte=label_created_at_lte,
label_honeypot_mark_gte=label_honeypot_mark_gte,
label_honeypot_mark_lte=label_honeypot_mark_lte,
label_type_in=label_type_in,
metadata_where=metadata_where,
skipped=skipped,
status_in=status_in,
updated_at_gte=updated_at_gte,
updated_at_lte=updated_at_lte,
label_category_search=label_category_search,
created_at_gte=created_at_gte,
created_at_lte=created_at_lte,
label_labeler_in=label_labeler_in,
label_labeler_not_in=label_labeler_not_in,
label_reviewer_in=label_reviewer_in,
label_reviewer_not_in=label_reviewer_not_in,
assignee_in=assignee_in,
assignee_not_in=assignee_not_in,
issue_status=issue_status,
issue_type=issue_type,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_status_in=step_status_in,
step_status_not_in=step_status_not_in,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
group_name_in=group_name_in if group_name_in else None,
group_name_not_in=group_name_not_in if group_name_not_in else None,
)
assets_gen = asset_use_cases.list_assets(
filters,
fields,
download_media=download_media,
local_media_dir=local_media_dir,
label_output_format=label_output_format,
options=QueryOptions(disable_tqdm=disable_tqdm, first=first, skip=skip),
)
if format == "pandas":
try:
import pandas as pd # pylint: disable=import-outside-toplevel
except ImportError as e:
raise ImportError("Install `pip install kili[pandas]` for format='pandas'.") from e
return pd.DataFrame(list(assets_gen))
if as_generator:
return assets_gen
return list(assets_gen)
count_assets(self, project_id, asset_id=None, asset_id_in=None, asset_id_not_in=None, metadata_where=None, status_in=None, label_type_in=None, label_author_in=None, label_created_at=None, skipped=None, updated_at_gte=None, updated_at_lte=None, label_category_search=None, created_at_gte=None, created_at_lte=None, honeypot_mark_gte=None, honeypot_mark_lte=None, consensus_mark_gte=None, consensus_mark_lte=None, inference_mark_gte=None, inference_mark_lte=None, label_labeler_in=None, label_labeler_not_in=None, label_reviewer_in=None, label_reviewer_not_in=None, assignee_in=None, assignee_not_in=None, label_consensus_mark_gte=None, label_consensus_mark_lte=None, label_created_at_gte=None, label_created_at_lte=None, label_honeypot_mark_gte=None, label_honeypot_mark_lte=None, issue_type=None, issue_status=None, external_id_strictly_in=None, external_id_in=None, step_name_in=None, step_name_not_in=None, step_status_in=None, step_status_not_in=None, step_name_and_status_in=None, step_name_and_status_not_in=None, group_name_in=None, group_name_not_in=None, step_id_in=None, step_id_not_in=None, step_id_and_status_in=None, step_id_and_status_not_in=None)
Count and return the number of assets with the given constraints.
Parameters beginning with 'label_' apply to labels, others apply to assets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id |
str |
Identifier of the project |
required |
asset_id |
Optional[str] |
The unique id of the asset to retrieve. |
None |
asset_id_in |
Optional[list[str]] |
A list of the ids of the assets to retrieve. |
None |
asset_id_not_in |
Optional[list[str]] |
A list of the ids of the assets to exclude. |
None |
metadata_where |
Optional[dict] |
Filters by the values of the metadata of the asset. |
None |
status_in |
Optional[list[Literal['TODO', 'ONGOING', 'LABELED', 'REVIEWED', 'TO_REVIEW']]] |
Returned assets should have a status that belongs to that list, if given. Possible choices: |
None |
label_type_in |
Optional[list[Literal['AUTOSAVE', 'DEFAULT', 'INFERENCE', 'PREDICTION', 'REVIEW']]] |
Returned assets should have a label whose type belongs to that list, if given. |
None |
label_author_in |
Optional[list[str]] |
Returned assets should have a label whose author belongs to that list, if given. An author can be designated by the first name, the last name, or the first name + last name. |
None |
label_created_at |
Optional[str] |
Returned assets should have a label whose creation date is equal to this date. |
None |
skipped |
Optional[bool] |
Returned assets should be skipped. |
None |
updated_at_gte |
Optional[str] |
Returned assets should have an update date that is greated or equal to this date. The update date represents the last time a modification has been done at the asset level. |
None |
updated_at_lte |
Optional[str] |
Returned assets should have an update date that is lower or equal to this date. The update date represents the last time a modification has been done at the asset level. |
None |
label_category_search |
Optional[str] |
Returned assets should have a label that follows this category search query. |
None |
created_at_gte |
Optional[str] |
Returned assets should have their import date greater or equal to this date. |
None |
created_at_lte |
Optional[str] |
Returned assets should have their import date lower or equal to this date. |
None |
honeypot_mark_lte |
Optional[float] |
Maximum amount of honeypot for the asset. |
None |
honeypot_mark_gte |
Optional[float] |
Minimum amount of honeypot for the asset. |
None |
consensus_mark_lte |
Optional[float] |
Maximum amount of consensus for the asset. |
None |
consensus_mark_gte |
Optional[float] |
Minimum amount of consensus for the asset. |
None |
inference_mark_gte |
Optional[float] |
Minimum amount of human/model IoU for the asset. |
None |
inference_mark_lte |
Optional[float] |
Maximum amount of human/model IoU for the asset. |
None |
label_labeler_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose labeler belongs to that list, if given. |
None |
label_labeler_not_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose labeler does not belong to that list, if given. |
None |
label_reviewer_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose reviewer belongs to that list, if given. |
None |
label_reviewer_not_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have a label whose reviewer does not belong to that list, if given. |
None |
assignee_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have an assigned user that belongs to that list, if given. |
None |
assignee_not_in |
Union[list[str], tuple[str, ...]] |
Returned assets should have an assigned user that does not belong to that list, if given. |
None |
label_consensus_mark_gte |
Optional[float] |
Returned assets should have a label whose consensus is greater or equal to this number. |
None |
label_consensus_mark_lte |
Optional[float] |
Returned assets should have a label whose consensus is lower or equal to this number. |
None |
label_created_at_lte |
Optional[str] |
Returned assets should have a label whose creation date is lower or equal to this date. |
None |
label_created_at_gte |
Optional[str] |
Returned assets should have a label whose creation date is greater or equal to this date. |
None |
label_honeypot_mark_gte |
Optional[float] |
Returned assets should have a label whose honeypot is greater or equal to this number. |
None |
label_honeypot_mark_lte |
Optional[float] |
Returned assets should have a label whose honeypot is lower or equal to this number. |
None |
issue_type |
Optional[Literal['ISSUE', 'QUESTION']] |
Returned assets should have issues of type |
None |
issue_status |
Optional[Literal['CANCELLED', 'OPEN', 'SOLVED']] |
Returned assets should have issues of status |
None |
external_id_strictly_in |
Optional[list[str]] |
Returned assets should have external ids that match exactly the ones in the list. |
None |
external_id_in |
Optional[list[str]] |
Returned assets should have external ids that partially match the ones in the list.
For example, with |
None |
step_name_in |
Optional[list[str]] |
Returned assets are in a step whose name belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
step_name_not_in |
Optional[list[str]] |
Returned assets are in a step whose name does not belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
step_id_in |
Optional[list[str]] |
Returned assets are in the step whose id belong to that list, if given.
Exclusive with |
None |
step_id_not_in |
Optional[list[str]] |
Returned assets are in the step whose id does not belong to that list,
if given. Exclusive with |
None |
step_id_and_status_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets match at least one of the given
(step_id, step_status) pairs. Exclusive with |
None |
step_id_and_status_not_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets do not match any of the given
(step_id, step_status) pairs. Exclusive with |
None |
step_status_in |
Optional[list[Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]] |
Returned assets have the status of their step that belongs to that list, if given.
Possible choices: |
None |
step_status_not_in |
Optional[list[Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]] |
Returned assets have the status of their step that does not belong to that list, if given.
Possible choices: |
None |
step_name_and_status_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets match at least one of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
step_name_and_status_not_in |
Optional[list[tuple[str, Literal['TO_DO', 'DOING', 'IN_PROGRESS', 'PARTIALLY_DONE', 'REWORK', 'REDO', 'DONE', 'SKIPPED']]]] |
Returned assets do not match any of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless |
None |
group_name_in |
Optional[list[str]] |
Returned assets belong to a workflow step group whose name is in the list, if given. Only applicable if the project uses the multi-group workflow. |
None |
group_name_not_in |
Optional[list[str]] |
Returned assets do not belong to a workflow step group whose name is in the list, if given. Only applicable if the project uses the multi-group workflow. |
None |
Dates format
Date strings should have format: "YYYY-MM-DD"
Returns:
| Type | Description |
|---|---|
int |
The number of assets that match the given constraints. |
Examples:
>>> kili.count_assets(project_id=project_id)
250
>>> kili.count_assets(asset_id=asset_id)
1
How to filter based on Metadata
metadata_where = {key1: "value1"}to filter on assets whose metadata have key "key1" with value "value1"metadata_where = {key1: ["value1", "value2"]}to filter on assets whose metadata have key "key1" with value "value1" or value "value2metadata_where = {key2: [2, 10]}to filter on assets whose metadata have key "key2" with a value between 2 and 10.
Source code in kili/presentation/client/asset.py
def count_assets(
self,
project_id: str,
asset_id: Optional[str] = None,
asset_id_in: Optional[list[str]] = None,
asset_id_not_in: Optional[list[str]] = None,
metadata_where: Optional[dict] = None,
status_in: Optional[list[AssetStatus]] = None,
label_type_in: Optional[list[LabelType]] = None,
label_author_in: Optional[list[str]] = None,
label_created_at: Optional[str] = None,
skipped: Optional[bool] = None,
updated_at_gte: Optional[str] = None,
updated_at_lte: Optional[str] = None,
label_category_search: Optional[str] = None,
created_at_gte: Optional[str] = None,
created_at_lte: Optional[str] = None,
honeypot_mark_gte: Optional[float] = None,
honeypot_mark_lte: Optional[float] = None,
consensus_mark_gte: Optional[float] = None,
consensus_mark_lte: Optional[float] = None,
inference_mark_gte: Optional[float] = None,
inference_mark_lte: Optional[float] = None,
label_labeler_in: Optional[ListOrTuple[str]] = None,
label_labeler_not_in: Optional[ListOrTuple[str]] = None,
label_reviewer_in: Optional[ListOrTuple[str]] = None,
label_reviewer_not_in: Optional[ListOrTuple[str]] = None,
assignee_in: Optional[ListOrTuple[str]] = None,
assignee_not_in: Optional[ListOrTuple[str]] = None,
label_consensus_mark_gte: Optional[float] = None,
label_consensus_mark_lte: Optional[float] = None,
label_created_at_gte: Optional[str] = None,
label_created_at_lte: Optional[str] = None,
label_honeypot_mark_gte: Optional[float] = None,
label_honeypot_mark_lte: Optional[float] = None,
issue_type: Optional[IssueType] = None,
issue_status: Optional[IssueStatus] = None,
external_id_strictly_in: Optional[list[str]] = None,
external_id_in: Optional[list[str]] = None,
step_name_in: Optional[list[str]] = None,
step_name_not_in: Optional[list[str]] = None,
step_status_in: Optional[list[StatusInStep]] = None,
step_status_not_in: Optional[list[StatusInStep]] = None,
step_name_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_name_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
group_name_in: Optional[list[str]] = None,
group_name_not_in: Optional[list[str]] = None,
step_id_in: Optional[list[str]] = None,
step_id_not_in: Optional[list[str]] = None,
step_id_and_status_in: Optional[list[tuple[str, StatusInStep]]] = None,
step_id_and_status_not_in: Optional[list[tuple[str, StatusInStep]]] = None,
) -> int:
# pylint: disable=line-too-long
"""Count and return the number of assets with the given constraints.
Parameters beginning with 'label_' apply to labels, others apply to assets.
Args:
project_id: Identifier of the project
asset_id: The unique id of the asset to retrieve.
asset_id_in: A list of the ids of the assets to retrieve.
asset_id_not_in: A list of the ids of the assets to exclude.
metadata_where: Filters by the values of the metadata of the asset.
status_in: Returned assets should have a status that belongs to that list, if given. Possible choices: `TODO`, `ONGOING`, `LABELED`, `TO_REVIEW` or `REVIEWED`.
label_type_in: Returned assets should have a label whose type belongs to that list, if given.
label_author_in: Returned assets should have a label whose author belongs to that list, if given. An author can be designated by the first name, the last name, or the first name + last name.
label_created_at: Returned assets should have a label whose creation date is equal to this date.
skipped: Returned assets should be skipped.
updated_at_gte: Returned assets should have an update date that is greated or equal to this date. The update date represents the last time a modification has been done at the asset level.
updated_at_lte: Returned assets should have an update date that is lower or equal to this date. The update date represents the last time a modification has been done at the asset level.
label_category_search: Returned assets should have a label that follows this category search query.
created_at_gte: Returned assets should have their import date greater or equal to this date.
created_at_lte: Returned assets should have their import date lower or equal to this date.
honeypot_mark_lte: Maximum amount of honeypot for the asset.
honeypot_mark_gte: Minimum amount of honeypot for the asset.
consensus_mark_lte: Maximum amount of consensus for the asset.
consensus_mark_gte: Minimum amount of consensus for the asset.
inference_mark_gte: Minimum amount of human/model IoU for the asset.
inference_mark_lte: Maximum amount of human/model IoU for the asset.
label_labeler_in: Returned assets should have a label whose labeler belongs to that list, if given.
label_labeler_not_in: Returned assets should have a label whose labeler does not belong to that list, if given.
label_reviewer_in: Returned assets should have a label whose reviewer belongs to that list, if given.
label_reviewer_not_in: Returned assets should have a label whose reviewer does not belong to that list, if given.
assignee_in: Returned assets should have an assigned user that belongs to that list, if given.
assignee_not_in: Returned assets should have an assigned user that does not belong to that list, if given.
label_consensus_mark_gte: Returned assets should have a label whose consensus is greater or equal to this number.
label_consensus_mark_lte: Returned assets should have a label whose consensus is lower or equal to this number.
label_created_at_lte: Returned assets should have a label whose creation date is lower or equal to this date.
label_created_at_gte: Returned assets should have a label whose creation date is greater or equal to this date.
label_honeypot_mark_gte: Returned assets should have a label whose honeypot is greater or equal to this number.
label_honeypot_mark_lte: Returned assets should have a label whose honeypot is lower or equal to this number.
issue_type: Returned assets should have issues of type `QUESTION` or `ISSUE`.
issue_status: Returned assets should have issues of status `OPEN` or `SOLVED`.
external_id_strictly_in: Returned assets should have external ids that match exactly the ones in the list.
external_id_in: Returned assets should have external ids that partially match the ones in the list.
For example, with `external_id_in=['abc']`, any asset with an external id containing `'abc'` will be returned.
step_name_in: Returned assets are in a step whose name belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_not_in: Returned assets are in a step whose name does not belong to that list, if given.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_id_in: Returned assets are in the step whose id belong to that list, if given.
Exclusive with `step_name_in`. Only applicable if the project uses the multi-step or multi-group workflow.
step_id_not_in: Returned assets are in the step whose id does not belong to that list,
if given. Exclusive with `step_name_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_in: Returned assets match at least one of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_id_and_status_not_in: Returned assets do not match any of the given
(step_id, step_status) pairs. Exclusive with `step_name_and_status_not_in`.
Only applicable if the project uses the multi-step or multi-group workflow.
step_status_in: Returned assets have the status of their step that belongs to that list, if given.
Possible choices: `TO_DO`, `DOING`, `IN_PROGRESS`, `PARTIALLY_DONE`, `REWORK`, `REDO`, `DONE`, `SKIPPED`.
Only applicable if the project uses the multi-step or multi-group workflow. Note that `DOING` and `REDO` are deprecated, use `IN_PROGRESS` and `REWORK` instead.
step_status_not_in: Returned assets have the status of their step that does not belong to that list, if given.
Possible choices: `TO_DO`, `DOING`, `IN_PROGRESS`, `PARTIALLY_DONE`, `REWORK`, `REDO`, `DONE`, `SKIPPED`.
Only applicable if the project uses the multi-step or multi-group workflow. Note that `DOING` and `REDO` are deprecated, use `IN_PROGRESS` and `REWORK` instead.
step_name_and_status_in: Returned assets match at least one of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
step_name_and_status_not_in: Returned assets do not match any of the given (step_name, step_status) pairs.
Only applicable if the project uses the multi-step or multi-group workflow.
Step names are unique per group only: a name several groups use matches the step
of each of them, unless `group_name_in` narrows it down.
group_name_in: Returned assets belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
group_name_not_in: Returned assets do not belong to a workflow step group whose name is in the list, if given.
Only applicable if the project uses the multi-group workflow.
!!! info "Dates format"
Date strings should have format: "YYYY-MM-DD"
Returns:
The number of assets that match the given constraints.
Examples:
>>> kili.count_assets(project_id=project_id)
250
>>> kili.count_assets(asset_id=asset_id)
1
!!! example "How to filter based on Metadata"
- `metadata_where = {key1: "value1"}` to filter on assets whose metadata
have key "key1" with value "value1"
- `metadata_where = {key1: ["value1", "value2"]}` to filter on assets whose metadata
have key "key1" with value "value1" or value "value2
- `metadata_where = {key2: [2, 10]}` to filter on assets whose metadata
have key "key2" with a value between 2 and 10.
"""
if (step_status_in is not None and "DOING" in step_status_in) or (
step_status_not_in is not None and "DOING" in step_status_not_in
):
warnings.warn(
"Step status 'DOING' is deprecated, use 'IN_PROGRESS' instead",
DeprecationWarning,
stacklevel=1,
)
if (step_status_in is not None and "REDO" in step_status_in) or (
step_status_not_in is not None and "REDO" in step_status_not_in
):
warnings.warn(
"Step status 'REDO' is deprecated, use 'REWORK' instead",
DeprecationWarning,
stacklevel=1,
)
has_step_or_status_filters = (
step_id_in is not None
or step_id_not_in is not None
or step_id_and_status_in is not None
or step_id_and_status_not_in is not None
or step_name_in is not None
or step_name_not_in is not None
or step_name_and_status_in is not None
or step_name_and_status_not_in is not None
or status_in is not None
or step_status_in is not None
or step_status_not_in is not None
or group_name_in is not None
or group_name_not_in is not None
)
if has_step_or_status_filters:
project_use_cases = ProjectUseCases(self.kili_api_gateway)
(
project_steps,
project_workflow_version,
) = project_use_cases.get_project_steps_and_version(project_id)
check_asset_workflow_arguments(
project_workflow_version=project_workflow_version,
asset_workflow_filters={
"skipped": skipped,
"step_name_in": step_name_in,
"has_step_id_filter": any(
f is not None
for f in (
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
)
),
"step_name_and_status_in": step_name_and_status_in,
"step_name_and_status_not_in": step_name_and_status_not_in,
"step_name_not_in": step_name_not_in,
"step_status_in": step_status_in,
"step_status_not_in": step_status_not_in,
"status_in": status_in,
"group_name_in": group_name_in,
"group_name_not_in": group_name_not_in,
},
)
if project_workflow_version in ("V2", "V3"):
(
step_id_in,
step_id_not_in,
step_id_and_status_in,
step_id_and_status_not_in,
) = resolve_step_filters(
project_steps,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
step_name_in=step_name_in,
step_name_not_in=step_name_not_in,
step_name_and_status_in=step_name_and_status_in,
step_name_and_status_not_in=step_name_and_status_not_in,
)
filters = AssetFilters(
project_id=ProjectId(project_id),
asset_id=AssetId(asset_id) if asset_id else None,
asset_id_in=cast(list[AssetId], asset_id_in) if asset_id_in else None,
asset_id_not_in=cast(list[AssetId], asset_id_not_in) if asset_id_not_in else None,
consensus_mark_gte=consensus_mark_gte,
consensus_mark_lte=consensus_mark_lte,
external_id_strictly_in=(
cast(list[AssetExternalId], external_id_strictly_in)
if external_id_strictly_in
else None
),
external_id_in=cast(list[AssetExternalId], external_id_in) if external_id_in else None,
honeypot_mark_gte=honeypot_mark_gte,
honeypot_mark_lte=honeypot_mark_lte,
inference_mark_gte=inference_mark_gte,
inference_mark_lte=inference_mark_lte,
label_author_in=label_author_in,
label_labeler_in=label_labeler_in,
label_labeler_not_in=label_labeler_not_in,
label_reviewer_in=label_reviewer_in,
label_reviewer_not_in=label_reviewer_not_in,
assignee_in=assignee_in,
assignee_not_in=assignee_not_in,
label_consensus_mark_gte=label_consensus_mark_gte,
label_consensus_mark_lte=label_consensus_mark_lte,
label_created_at=label_created_at,
label_created_at_gte=label_created_at_gte,
label_created_at_lte=label_created_at_lte,
label_honeypot_mark_gte=label_honeypot_mark_gte,
label_honeypot_mark_lte=label_honeypot_mark_lte,
label_type_in=label_type_in,
metadata_where=metadata_where,
skipped=skipped,
status_in=status_in,
updated_at_gte=updated_at_gte,
updated_at_lte=updated_at_lte,
label_category_search=label_category_search,
created_at_gte=created_at_gte,
created_at_lte=created_at_lte,
issue_status=issue_status,
issue_type=issue_type,
step_id_and_status_in=step_id_and_status_in,
step_id_and_status_not_in=step_id_and_status_not_in,
step_id_in=step_id_in,
step_id_not_in=step_id_not_in,
step_status_in=step_status_in,
step_status_not_in=step_status_not_in,
group_name_in=group_name_in if group_name_in else None,
group_name_not_in=group_name_not_in if group_name_not_in else None,
)
asset_use_cases = AssetUseCases(self.kili_api_gateway)
return asset_use_cases.count_assets(filters)
update_asset_consensus(self, project_id, is_consensus, asset_id=None, external_id=None)
Activate or deactivate consensus on an asset.
This method is not compatible with projects using the legacy workflow. On those projects,
use kili.update_properties_in_assets() with is_used_for_consensus_array instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id |
str |
The project ID. |
required |
is_consensus |
bool |
Whether to activate (True) or deactivate (False) consensus on the asset. |
required |
asset_id |
Optional[str] |
The internal asset ID to modify. Either asset_id or external_id must be provided. |
None |
external_id |
Optional[str] |
The external ID of the asset to modify. Either asset_id or external_id must be provided. |
None |
Returns:
| Type | Description |
|---|---|
bool |
The consensus value that was set (True if consensus was activated, False if deactivated). |
Exceptions:
| Type | Description |
|---|---|
ValueError |
If neither asset_id nor external_id is provided. |
GraphQLError |
If a server-side precondition is not met. The server accepts the call only on multi-step or multi-group workflow projects, while the asset sits on a labeling (DEFAULT) step whose status is still TO_DO, when consensus is enabled on that step, and when the caller is an admin or a team manager. Note that the TO_DO window closes as soon as any labeler starts working on the asset (their first autosave, not their submission), so the real precondition is that no labeler has opened and started the asset yet. |
Examples:
>>> # Activate consensus on an asset using asset_id
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=True,
... asset_id="ckg22d81r0jrg0885unmuswj8"
... )
>>> # result is True
>>> # Activate consensus on an asset using external_id
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=True,
... external_id="my_asset_001"
... )
>>> # result is True
>>> # Deactivate consensus on an asset
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=False,
... asset_id="ckg22d81r0jrg0885unmuswj8"
... )
>>> # result is False
Source code in kili/presentation/client/asset.py
def update_asset_consensus(
self,
project_id: str,
is_consensus: bool,
asset_id: Optional[str] = None,
external_id: Optional[str] = None,
) -> bool:
"""Activate or deactivate consensus on an asset.
This method is not compatible with projects using the legacy workflow. On those projects,
use `kili.update_properties_in_assets()` with `is_used_for_consensus_array` instead.
Args:
project_id: The project ID.
is_consensus: Whether to activate (True) or deactivate (False) consensus on the asset.
asset_id: The internal asset ID to modify. Either asset_id or external_id must be provided.
external_id: The external ID of the asset to modify. Either asset_id or external_id must be provided.
Returns:
The consensus value that was set (True if consensus was activated, False if deactivated).
Raises:
ValueError: If neither asset_id nor external_id is provided.
GraphQLError: If a server-side precondition is not met. The server accepts the
call only on multi-step or multi-group workflow projects, while the asset sits on
a labeling (DEFAULT) step whose status is still TO_DO, when consensus is enabled
on that step, and when the caller is an admin or a team manager. Note that the TO_DO
window closes as soon as any labeler starts working on the asset (their first
autosave, not their submission), so the real precondition is that no labeler
has opened and started the asset yet.
Examples:
>>> # Activate consensus on an asset using asset_id
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=True,
... asset_id="ckg22d81r0jrg0885unmuswj8"
... )
>>> # result is True
>>> # Activate consensus on an asset using external_id
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=True,
... external_id="my_asset_001"
... )
>>> # result is True
>>> # Deactivate consensus on an asset
>>> result = kili.update_asset_consensus(
... project_id="my_project",
... is_consensus=False,
... asset_id="ckg22d81r0jrg0885unmuswj8"
... )
>>> # result is False
"""
if asset_id is None and external_id is None:
raise ValueError(
"At least one of asset_id or external_id must be provided to update_asset_consensus"
)
return self.kili_api_gateway.update_asset_consensus(
project_id=project_id,
is_consensus=is_consensus,
asset_id=asset_id,
external_id=external_id,
)
Set of Asset mutations.
Source code in kili/entrypoints/mutations/asset/__init__.py
@for_all_methods(log_call, exclude=["__init__"])
class MutationsAsset(BaseOperationEntrypointMixin):
"""Set of Asset mutations."""
# pylint: disable=too-many-arguments,too-many-locals
@typechecked
def append_many_to_dataset(
self,
project_id: str,
content_array: Optional[Union[list[str], list[dict], list[list[dict]]]] = None,
multi_layer_content_array: Optional[list[list[dict]]] = None,
external_id_array: Optional[list[str]] = None,
id_array: Optional[list[str]] = None,
is_honeypot_array: Optional[list[bool]] = None,
status_array: Optional[list[str]] = None,
json_content_array: Optional[list[Union[list[Union[dict, str]], None]]] = None,
json_metadata_array: Optional[list[dict]] = None,
disable_tqdm: Optional[bool] = None,
wait_until_availability: bool = True,
from_csv: Optional[str] = None,
csv_separator: str = ",",
) -> dict[Literal["id", "asset_ids"], Union[str, list[str]]]:
# pylint: disable=line-too-long
"""Append assets to a project.
Args:
project_id: Identifier of the project
content_array: List of elements added to the assets of the project
Must not be None except if you provide multi_layer_content_array or json_content_array.
- For a `TEXT` project, the content can be either raw text, or URLs to TEXT assets.
- For an `IMAGE` / `PDF` project, the content can be either URLs or paths to existing
images/pdf on your computer.
- For a VIDEO project, the content can be either URLs pointing to videos hosted on a web server or paths to
existing video files on your computer. If you want to import video from frames, look at the json_content
section below.
- For an `VIDEO_LEGACY` project, the content can be only be URLs.
- For an `LLM_RLHF` project, the content can be dicts with the keys `prompt` and `completions`,
paths to local json files or URLs to json files.
multi_layer_content_array: List containing multiple lists of paths.
Each path correspond to a layer of a geospatial asset. Should be used only for `IMAGE` and `GEOSPATIAL` projects.
external_id_array: List of external ids given to identify the assets.
If None, random identifiers are created.
id_array: Disabled parameter. Do not use.
is_honeypot_array: Whether to use the asset for honeypot
status_array: DEPRECATED and does not have any effect.
json_content_array: Useful for `VIDEO` or `TEXT` or `IMAGE` projects only.
- For `VIDEO` projects, each element is a sequence of frames, i.e. a
list of URLs to images or a list of paths to images.
- For `TEXT` projects, each element is a json_content dict,
formatted according to documentation [on how to import
rich-text assets](https://python-sdk-docs.kili-technology.com/latest/sdk/tutorials/import_text_assets/).
- For `IMAGES` projects, it is used for satellite imagery each element is a list of json_content dicts
formatted according to documentation [on how to add multi-layer images]
(https://docs.kili-technology.com/docs/adding-assets-to-project#adding-multi-layer-images)
json_metadata_array: The metadata given to each asset should be stored in a json like dict with keys.
- Add metadata visible on the asset
Example for one asset: `json_metadata_array = [{'imageUrl': '','text': '','url': '','key1': 'value1'}]`.
- For VIDEO projects (and not VIDEO_LEGACY), you can specify a value with key 'processingParameters' to specify the sampling rate (default: 30).
Example for one asset: `json_metadata_array = [{'processingParameters': {'framesPlayedPerSecond': 10}}]`.
- In Image projects with geoTIFF assets, you can specify the epsg, the `minZoom` and `maxZoom` values for the `processingParameters` key.
- The epsg is a number that defines the projection that will be used for the asset. Values that can be used are either 4326 or 3857, the 2
projections that we support. If this number is not set, by default we keep the initial projection of the asset if it is 4326 or 3857, either
we reproject the asset to EPSG:3857 by default.
- The `minZoom` parameter defines the zoom level that users are not allowed to zoom out from. It also affects the zoom levels for which we
generate the tiles when tiling the asset (for asset with size > 30MB).
- The `maxZoom` value affects asset generation: the higher the value, the greater the level of details and the size of the asset. It also affects
the zoom levels for which we generate the tiles when tiling the asset (for asset with size > 30MB).
- Example for one asset: `json_metadata_array = [{'processingParameters': {'epsg': 3758, 'minZoom': 17, 'maxZoom': 19}}]`.
disable_tqdm: If `True`, the progress bar will be disabled
wait_until_availability: If `True`, the function will return once the assets are fully imported in Kili.
If `False`, the function will return faster but the assets might not be fully processed by the server.
from_csv: Path to a csv file containing the text assets to import.
Only used for `TEXT` projects.
If provided, `content_array` and `external_id_array` must be None.
The csv file header must specify the columns `content` and `externalId`.
csv_separator: Separator used in the csv file. Only used if `from_csv` is provided.
Returns:
A dictionary with two fields: `id` which is the project id and `asset_ids` which is a list of the created asset ids.
In the case where assets are uploaded asynchronously (for video imported as frames or big images or tiff images), the method return an empty list of asset ids.
Examples:
>>> kili.append_many_to_dataset(
project_id=project_id,
content_array=['https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'])
!!! example "Recipe"
- For more detailed examples on how to import assets,
see [the recipe](https://docs.kili-technology.com/recipes/importing-data).
- For more detailed examples on how to import text assets,
see [the recipe](https://python-sdk-docs.kili-technology.com/latest/sdk/tutorials/import_text_assets/).
"""
if from_csv is not None:
if content_array is not None or external_id_array is not None:
raise ValueError(
"If from_csv is provided, content_array and external_id_array must not be"
" provided."
)
content_array, external_id_array = get_text_assets_from_csv(
from_csv=from_csv, csv_separator=csv_separator
)
if (
is_empty_list_with_warning("append_many_to_dataset", "content_array", content_array)
or is_empty_list_with_warning(
"append_many_to_dataset", "json_content_array", json_content_array
)
or is_empty_list_with_warning(
"append_many_to_dataset", "multi_layer_content_array", multi_layer_content_array
)
):
return {"id": project_id, "asset_ids": []}
if status_array is not None:
warnings.warn(
"status_array is deprecated and will not be sent in the call. Asset status is"
" automatically computed based on its labels and cannot be overwritten.",
DeprecationWarning,
stacklevel=1,
)
if (
content_array is None
and multi_layer_content_array is None
and json_content_array is None
):
raise ValueError(
"Variables content_array, multi_layer_content_array and json_content_array cannot be both None."
)
if content_array is not None and multi_layer_content_array is not None:
raise ValueError(
"Variables content_array and multi_layer_content_array cannot be both provided."
)
nb_data = (
len(content_array)
if content_array is not None
else (
len(multi_layer_content_array)
if multi_layer_content_array is not None
else len(json_content_array) # type:ignore
)
)
field_mapping = {
"content": content_array,
"multi_layer_content": multi_layer_content_array,
"json_content": json_content_array,
"external_id": external_id_array,
"id": id_array,
"json_metadata": json_metadata_array,
"is_honeypot": is_honeypot_array,
}
assets = [{}] * nb_data
for key, value in field_mapping.items():
if value is not None:
assets = [{**assets[i], key: value[i]} for i in range(nb_data)]
created_asset_ids = import_assets(
self, # pyright: ignore[reportArgumentType]
project_id=ProjectId(project_id),
assets=assets,
disable_tqdm=disable_tqdm,
verify=wait_until_availability,
)
return {"id": project_id, "asset_ids": created_asset_ids}
@typechecked
def assign_assets_to_labelers(
self,
to_be_labeled_by_array: list[list[str]],
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Assign a list of assets to a list of labelers.
Assigning an asset to nobody unassigns it. A labeler who has a label in progress on an
asset stays assigned to it whatever this asks for: unassigning them would leave them with
an interface they can no longer submit from, and the asset in progress with nobody to
finish it. Those assets are reported under `declined` rather than silently left out.
Args:
asset_ids: The internal asset IDs to assign.
external_ids: The external asset IDs to assign (if `asset_ids` is not already provided).
project_id: The project ID. Only required if `external_ids` argument is provided.
to_be_labeled_by_array: The array of list of labelers to assign per labelers (list of userIds).
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.assign_assets_to_labelers(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
to_be_labeled_by_array=[['cm3yja6kv0i698697gcil9rtk','cm3yja6kv0i000000gcil9rtk'],
['cm3yja6kv0i698697gcil9rtk']]
)
# The following call resets the assignees on the asset_ids given.
>>> kili.assign_assets_to_labelers(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
to_be_labeled_by_array=[[], []]
)
"""
if is_empty_list_with_warning(
"assign_assets_to_labelers", "asset_ids", asset_ids
) and is_empty_list_with_warning("assign_assets_to_labelers", "external_ids", external_ids):
return empty_asset_action_outcome()
if (asset_ids is not None and external_ids is not None) or (
asset_ids is None and external_ids is None
):
raise MissingArgumentError("Please provide either `asset_ids` or `external_ids`.")
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
if len(resolved_asset_ids) != len(to_be_labeled_by_array):
raise MutationError("There must be as many assets as there are lists of labelers.")
# Group assets by assignee list to batch
# assignee combination instead of 1 call per asset.
groups: dict[tuple, list[str]] = {}
for asset_id, to_be_labeled_by in zip(
resolved_asset_ids, to_be_labeled_by_array, strict=False
):
key = tuple(to_be_labeled_by)
if key not in groups:
groups[key] = []
groups[key].append(asset_id)
outcome = empty_asset_action_outcome()
for user_ids_tuple, ids_for_group in groups.items():
group_outcome = execute_asset_action(
self.graphql_client,
GQL_ASSIGN_ASSETS,
ids_for_group,
{"userIds": list(user_ids_tuple)},
)
outcome["declined"].extend(group_outcome["declined"])
outcome["failed"].extend(group_outcome["failed"])
outcome["succeeded"].extend(group_outcome["succeeded"])
return outcome
@typechecked
def update_properties_in_assets(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
priorities: Optional[list[int]] = None,
json_metadatas: Optional[list[Union[dict, str]]] = None,
consensus_marks: Optional[list[float]] = None,
honeypot_marks: Optional[list[float]] = None,
to_be_labeled_by_array: Optional[list[list[str]]] = None,
contents: Optional[list[str]] = None,
json_contents: Optional[list[str]] = None,
status_array: Optional[list[str]] = None,
is_used_for_consensus_array: Optional[list[bool]] = None,
is_honeypot_array: Optional[list[bool]] = None,
project_id: Optional[str] = None,
resolution_array: Optional[list[dict]] = None,
page_resolutions_array: Optional[
Union[list[list[dict]], list[list[PageResolution]]]
] = None,
) -> list[dict[Literal["id"], str]]:
"""Update the properties of one or more assets.
Args:
asset_ids: The internal asset IDs to modify.
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
priorities: DEPRECATED, use `kili.set_assets_priority()` instead, which reports the
assets it could not be applied to. You can change the priority of the assets.
By default, all assets have a priority of 0.
json_metadatas: The metadata given to an asset should be stored
in a json like dict with keys `imageUrl`, `text`, `url`:
`json_metadata = {'imageUrl': '','text': '','url': ''}`
consensus_marks: Should be between 0 and 1.
honeypot_marks: Should be between 0 and 1.
to_be_labeled_by_array: If given, each element of the list should contain the emails of
the labelers authorized to label the asset.
contents: - For a NLP project, the content can be directly in text format.
- For an Image / Video / Pdf project, the content must be hosted on a web server,
and you point Kili to your data by giving the URLs.
json_contents: - For a NLP project, the `json_content`
is a text formatted using RichText.
- For a Video project, the`json_content` is a json containg urls pointing
to each frame of the video.
status_array: DEPRECATED and does not have any effect.
is_used_for_consensus_array: Whether to use the asset to compute consensus kpis or not.
Only supported in the legacy workflow; in the multi-step and multi-group workflows it
raises `DeprecatedArgumentError`, use `kili.update_asset_consensus()` instead.
is_honeypot_array: Whether to use the asset for honeypot.
project_id: The project ID. Only required if `external_ids` argument is provided.
resolution_array: The resolution of each asset (for image and video assets).
Each resolution must be passed as a dictionary with keys `width` and `height`.
page_resolutions_array: The resolution of each page of the asset (for PDF assets).
Note that each element of the array should contain all the pages resolutions of the
corresponding asset. Each resolution can be passed as a
`kili.utils.assets.PageResolution` object, or as a dictionary with keys `width`,
`height`, `pageNumber` and optionally `rotation`.
Returns:
A list of dictionaries with the asset ids.
Raises:
DeprecatedArgumentError: If `is_used_for_consensus_array` is used on a multi-step or
multi-group workflow project. Use `kili.update_asset_consensus()` for those
projects.
MissingArgumentError: If both `asset_ids` and `external_ids` are provided, or if
neither of them is.
GraphQLError: If the backend refuses the update for any other reason.
Examples:
>>> kili.update_properties_in_assets(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
consensus_marks=[1, 0.7],
contents=[None, 'https://to/second/asset.png'],
honeypot_marks=[0.8, 0.5],
is_honeypot_array=[True, True],
is_used_for_consensus_array=[True, False],
to_be_labeled_by_array=[['test+pierre@kili-technology.com'], None],
)
# The following call updates the pages resolutions of PDF assets.
>>> kili.update_properties_in_assets(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
page_resolutions_array=[
[
PageResolution(width=480, height=640, page_number=1),
PageResolution(width=480, height=640, page_number=2),
],[
PageResolution(width=340, height=512, page_number=1),
PageResolution(width=680, height=1024, page_number=2, rotation=90),
PageResolution(width=680, height=1024, page_number=3),
]
],
)
"""
if is_empty_list_with_warning(
"update_properties_in_assets", "asset_ids", asset_ids
) or is_empty_list_with_warning(
"update_properties_in_assets", "external_ids", external_ids
):
return []
if status_array is not None:
warnings.warn(
"status_array is deprecated and will not be sent in the call. Asset status is"
" automatically computed based on its labels and cannot be overwritten.",
DeprecationWarning,
stacklevel=1,
)
if asset_ids is not None and external_ids is not None:
warnings.warn(
"The use of `external_ids` argument has changed. It is now used to identify"
" which properties of which assets to update. Please use"
" `kili.change_asset_external_ids()` method instead to change asset external"
" IDs.",
DeprecationWarning,
stacklevel=1,
)
raise MissingArgumentError("Please provide either `asset_ids` or `external_ids`.")
if to_be_labeled_by_array is not None:
warnings.warn(
"to_be_labeled_by_array is going to be deprecated. Please use"
" `kili.assign_assets_to_labelers()` method instead to assign assets",
DeprecationWarning,
stacklevel=1,
)
if priorities is not None:
warnings.warn(
"priorities is deprecated: it does not report the assets it could not be applied"
" to. Please use `kili.set_assets_priority()` method instead to prioritize assets",
DeprecationWarning,
stacklevel=1,
)
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
properties_to_batch = process_update_properties_in_assets_parameters(
cast(list[str], resolved_asset_ids),
priorities=priorities,
json_metadatas=json_metadatas,
consensus_marks=consensus_marks,
honeypot_marks=honeypot_marks,
to_be_labeled_by_array=to_be_labeled_by_array,
contents=contents,
json_contents=json_contents,
is_used_for_consensus_array=is_used_for_consensus_array,
is_honeypot_array=is_honeypot_array,
resolution_array=resolution_array,
page_resolutions_array=page_resolutions_array,
)
def generate_variables(batch: dict) -> dict:
asset_ids = batch.pop("assetId")
data_array = [
dict(zip(batch, t, strict=False)) for t in zip(*batch.values(), strict=False)
] # type: ignore
return {
"whereArray": [{"id": asset_id} for asset_id in asset_ids],
"dataArray": data_array,
}
try:
results = mutate_from_paginated_call(
self,
properties_to_batch,
generate_variables,
GQL_UPDATE_PROPERTIES_IN_ASSETS,
)
except GraphQLError as err:
deprecation_message = _get_error_message_with_key(err, DEPRECATED_ERROR_KEY)
if deprecation_message is not None:
raise DeprecatedArgumentError(_to_sdk_method_names(deprecation_message)) from err
raise
formated_results = [self.format_result("data", result, None) for result in results]
return [item for batch_list in formated_results for item in batch_list]
@typechecked
def add_metadata(
self,
json_metadata: list[dict[str, Any]],
project_id: str,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
) -> list[dict[Literal["id"], str]]:
"""Add metadata to assets without overriding existing metadata.
Each dictionary is merged into the metadata of the asset given at the same position: its
keys are added, or changed when the asset already has them, and the other keys are kept. A
stored `ocrMetadata` key is the asset's OCR, not metadata: it is left out, and the OCR is
unchanged. The metadata is read, then written whole: two calls at once on the same asset may
lose the keys of one of them.
Args:
json_metadata: List of metadata dictionaries to add to each asset, one per asset, in
the order of `asset_ids` or `external_ids`. Values can be nested dicts and lists.
project_id: The project ID.
asset_ids: The asset IDs to modify.
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
They are matched exactly.
Returns:
A list of dictionaries with the asset ids.
Raises:
MissingArgumentError: If both or neither of `asset_ids` and `external_ids` are given.
IncompatibleArgumentsError: If `json_metadata` and the ids do not have the same length.
NotFound: If an asset ID or an external ID matches no asset of the project, or an
external ID several.
Examples:
>>> kili.add_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.add_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
"""
if is_empty_list_with_warning("add_metadata", "json_metadata", json_metadata):
return []
asset_ids_in_order, current_metadata = AssetUseCasesUtils(
self.kili_api_gateway
).get_metadata_targets(ProjectId(project_id), asset_ids, external_ids, len(json_metadata))
# an asset given twice gets both dictionaries, in order, in one update
new_metadata: dict[str, dict] = {}
for asset_id, metadata in zip(asset_ids_in_order, json_metadata, strict=True):
new_metadata[asset_id] = {
**new_metadata.get(asset_id, current_metadata[asset_id]),
**metadata,
}
return self.update_properties_in_assets(
asset_ids=list(new_metadata),
json_metadatas=list(new_metadata.values()),
)
@typechecked
def set_metadata(
self,
json_metadata: list[dict[str, Any]],
project_id: str,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
) -> list[dict[Literal["id"], str]]:
"""Set metadata on assets, replacing their existing metadata.
Each dictionary replaces the metadata of the asset given at the same position, except the
keys `text`, `imageUrl`, `url` and `processingParameters`, which the asset keeps unless the
dictionary gives them. The metadata is read, then written whole: two calls at once on the
same asset may lose the keys of one of them.
Args:
json_metadata: List of metadata dictionaries to set on each asset, one per asset, in
the order of `asset_ids` or `external_ids`. Values can be nested dicts and lists.
project_id: The project ID.
asset_ids: The asset IDs to modify (if `external_ids` is not already provided).
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
They are matched exactly.
Returns:
A list of dictionaries with the asset ids.
Raises:
MissingArgumentError: If both or neither of `asset_ids` and `external_ids` are given.
IncompatibleArgumentsError: If `json_metadata` and the ids do not have the same length.
NotFound: If an asset ID or an external ID matches no asset of the project, or an
external ID several.
Examples:
>>> kili.set_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.set_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
"""
if is_empty_list_with_warning("set_metadata", "json_metadata", json_metadata):
return []
asset_ids_in_order, current_metadata = AssetUseCasesUtils(
self.kili_api_gateway
).get_metadata_targets(ProjectId(project_id), asset_ids, external_ids, len(json_metadata))
# an asset given twice gets both dictionaries in turn, as two calls would
new_metadata: dict[str, dict] = {}
for asset_id, metadata in zip(asset_ids_in_order, json_metadata, strict=True):
kept_metadata = {
key: value
for key, value in new_metadata.get(asset_id, current_metadata[asset_id]).items()
if key in METADATA_KEYS_KEPT_BY_SET
}
new_metadata[asset_id] = {**kept_metadata, **metadata}
return self.update_properties_in_assets(
asset_ids=list(new_metadata),
json_metadatas=list(new_metadata.values()),
)
@typechecked
def remove_metadata(
self,
keys: list[str],
project_id: str,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
) -> list[dict[Literal["id"], str]]:
"""Remove metadata keys from assets, keeping their other keys.
A stored `ocrMetadata` key is the asset's OCR, not metadata: it is left out, and the OCR is
unchanged. The metadata is read, then written whole: two calls at once on the same asset may
lose the keys of one of them.
Args:
keys: The metadata keys to remove from each asset. A key an asset does not have is
ignored.
project_id: The project ID.
asset_ids: The asset IDs to modify (if `external_ids` is not already provided).
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
They are matched exactly.
Returns:
A list of dictionaries with the asset ids.
Raises:
ValueError: If `keys` holds `processingParameters`, which Kili keeps to process the
asset: change it with `add_metadata`, which keeps the asset's other metadata.
MissingArgumentError: If both or neither of `asset_ids` and `external_ids` are given.
NotFound: If an asset ID or an external ID matches no asset of the project, or an
external ID several.
Examples:
>>> kili.remove_metadata(
keys=["reviewed_by", "split"],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.remove_metadata(
keys=["reviewed_by"],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
"""
if (
is_empty_list_with_warning("remove_metadata", "keys", keys)
or is_empty_list_with_warning("remove_metadata", "asset_ids", asset_ids)
or is_empty_list_with_warning("remove_metadata", "external_ids", external_ids)
):
return []
if "processingParameters" in keys:
raise ValueError(
"`processingParameters` cannot be removed: Kili keeps it to process the asset."
' Change it with `add_metadata(json_metadata=[{"processingParameters": {...}}], ...)`,'
" which keeps the asset's other metadata."
)
asset_ids_in_order, current_metadata = AssetUseCasesUtils(
self.kili_api_gateway
).get_metadata_targets(ProjectId(project_id), asset_ids, external_ids)
new_metadata = {
asset_id: {
key: value for key, value in current_metadata[asset_id].items() if key not in keys
}
for asset_id in asset_ids_in_order
}
return self.update_properties_in_assets(
asset_ids=list(new_metadata),
json_metadatas=list(new_metadata.values()),
)
@typechecked
def change_asset_external_ids(
self,
new_external_ids: list[str],
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> list[dict[Literal["id"], str]]:
"""Update the external IDs of one or more assets.
Args:
new_external_ids: The new external IDs of the assets.
asset_ids: The asset IDs to modify.
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A list of dictionaries with the asset ids.
Examples:
>>> kili.change_asset_external_ids(
new_external_ids=["asset1", "asset2"],
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
)
"""
if is_empty_list_with_warning(
"change_asset_external_ids", "new_external_ids", new_external_ids
):
return []
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
properties_to_batch = process_update_properties_in_assets_parameters(
asset_ids=cast(list[str], resolved_asset_ids),
external_ids=new_external_ids,
)
def generate_variables(batch: dict) -> dict:
asset_ids = batch.pop("assetId")
data_array = [
dict(zip(batch, t, strict=False)) for t in zip(*batch.values(), strict=False)
] # type: ignore
return {
"whereArray": [{"id": asset_id} for asset_id in asset_ids],
"dataArray": data_array,
}
results = mutate_from_paginated_call(
self,
properties_to_batch,
generate_variables,
GQL_UPDATE_PROPERTIES_IN_ASSETS,
)
formated_results = [self.format_result("data", result, None) for result in results]
return [item for batch_list in formated_results for item in batch_list]
@typechecked
def delete_many_from_dataset(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Delete assets from a project.
A batch whose write failed is reported under `failed` rather than failing the call. An asset
already deleted, given by its id, is reported under `succeeded`: it is in the state that was
asked for.
Args:
asset_ids: The list of asset internal IDs to delete.
external_ids: The list of asset external IDs to delete.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.delete_many_from_dataset(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"delete_many_from_dataset", "asset_ids", asset_ids
) or is_empty_list_with_warning("delete_many_from_dataset", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(self.graphql_client, GQL_DELETE_ASSETS, resolved_asset_ids)
@typechecked
def add_to_review(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Add assets to review.
An asset without any label, or that cannot move on yet — its step is not done, someone is
labeling it — is reported under `declined` rather than silently left out.
Args:
asset_ids: The asset internal IDs to add to review.
external_ids: The asset external IDs to add to review.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.add_to_review(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"add_to_review", "asset_ids", asset_ids
) or is_empty_list_with_warning("add_to_review", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(
self.graphql_client, GQL_ADD_ASSETS_TO_REVIEW, resolved_asset_ids
)
@typechecked
def send_back_to_queue(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Send assets back to queue.
An asset the send back does not apply to — one still to be labeled, or, in the multi-step
and multi-group workflows, one skipped — comes back under `declined`, and one whose write
failed under `failed`.
Args:
asset_ids: List of internal IDs of assets to send back to queue.
external_ids: List of external IDs of assets to send back to queue.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.send_back_to_queue(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"send_back_to_queue", "asset_ids", asset_ids
) or is_empty_list_with_warning("send_back_to_queue", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(
self.graphql_client, GQL_SEND_ASSETS_BACK_TO_QUEUE, resolved_asset_ids
)
@typechecked
def set_assets_priority(
self,
priority: int,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Set the priority of assets.
An asset whose current step is not waiting for work — in progress, done or skipped — is
reported under `declined` rather than silently left out.
Args:
priority: The priority to give every asset. By default, all assets have a priority of 0.
asset_ids: The internal IDs of the assets to prioritize.
external_ids: The external IDs of the assets to prioritize.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.set_assets_priority(
priority=2,
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"set_assets_priority", "asset_ids", asset_ids
) or is_empty_list_with_warning("set_assets_priority", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(
self.graphql_client,
GQL_SET_ASSETS_PRIORITY,
resolved_asset_ids,
{"priority": priority},
)
def skip_or_unskip(
self,
action: Literal["skip", "unskip"],
asset_id: str,
project_id: str,
reason: Optional[str] = None,
) -> str:
"""Skip or unskip an asset.
An asset used for consensus cannot be skipped: skipping it would remove the asset from
the queue for every labeler assigned to it, not just the one requesting the skip.
Args:
action: The action you want to do. Either skip or unskip.
asset_id: ID of the asset you want to skip or unskip.
project_id: The project ID.
reason: The reason why you skip an asset. Only required if the action is `skip`.
Returns:
The asset ID of the asset modified. An error message if mutation failed.
Examples:
>>> kili.skip_or_unskip(
action="skip",
asset_id="ckg22d81s0jrh0885pdxfd03n",
project_id="ckg22d81r0jrg0885unmuswj8",
reason="Test"
)
"""
if action == "skip":
if reason is None:
raise MissingArgumentError("You must provide a reason to skip an asset")
payload = {"reason": reason, "where": {"id": asset_id, "project": {"id": project_id}}}
self.graphql_client.execute(GQL_SKIP_ASSET, payload)
else:
payload = {"projectId": project_id, "assetId": asset_id}
self.graphql_client.execute(GQL_UNSKIP_ASSET, payload)
return asset_id
add_metadata(self, json_metadata, project_id, asset_ids=None, external_ids=None)
Add metadata to assets without overriding existing metadata.
Each dictionary is merged into the metadata of the asset given at the same position: its
keys are added, or changed when the asset already has them, and the other keys are kept. A
stored ocrMetadata key is the asset's OCR, not metadata: it is left out, and the OCR is
unchanged. The metadata is read, then written whole: two calls at once on the same asset may
lose the keys of one of them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_metadata |
list |
List of metadata dictionaries to add to each asset, one per asset, in
the order of |
required |
project_id |
str |
The project ID. |
required |
asset_ids |
Optional[list[str]] |
The asset IDs to modify. |
None |
external_ids |
Optional[list[str]] |
The external asset IDs to modify (if |
None |
Returns:
| Type | Description |
|---|---|
list |
A list of dictionaries with the asset ids. |
Exceptions:
| Type | Description |
|---|---|
MissingArgumentError |
If both or neither of |
IncompatibleArgumentsError |
If |
NotFound |
If an asset ID or an external ID matches no asset of the project, or an external ID several. |
Examples:
>>> kili.add_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.add_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def add_metadata(
self,
json_metadata: list[dict[str, Any]],
project_id: str,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
) -> list[dict[Literal["id"], str]]:
"""Add metadata to assets without overriding existing metadata.
Each dictionary is merged into the metadata of the asset given at the same position: its
keys are added, or changed when the asset already has them, and the other keys are kept. A
stored `ocrMetadata` key is the asset's OCR, not metadata: it is left out, and the OCR is
unchanged. The metadata is read, then written whole: two calls at once on the same asset may
lose the keys of one of them.
Args:
json_metadata: List of metadata dictionaries to add to each asset, one per asset, in
the order of `asset_ids` or `external_ids`. Values can be nested dicts and lists.
project_id: The project ID.
asset_ids: The asset IDs to modify.
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
They are matched exactly.
Returns:
A list of dictionaries with the asset ids.
Raises:
MissingArgumentError: If both or neither of `asset_ids` and `external_ids` are given.
IncompatibleArgumentsError: If `json_metadata` and the ids do not have the same length.
NotFound: If an asset ID or an external ID matches no asset of the project, or an
external ID several.
Examples:
>>> kili.add_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.add_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
"""
if is_empty_list_with_warning("add_metadata", "json_metadata", json_metadata):
return []
asset_ids_in_order, current_metadata = AssetUseCasesUtils(
self.kili_api_gateway
).get_metadata_targets(ProjectId(project_id), asset_ids, external_ids, len(json_metadata))
# an asset given twice gets both dictionaries, in order, in one update
new_metadata: dict[str, dict] = {}
for asset_id, metadata in zip(asset_ids_in_order, json_metadata, strict=True):
new_metadata[asset_id] = {
**new_metadata.get(asset_id, current_metadata[asset_id]),
**metadata,
}
return self.update_properties_in_assets(
asset_ids=list(new_metadata),
json_metadatas=list(new_metadata.values()),
)
add_to_review(self, asset_ids=None, external_ids=None, project_id=None)
Add assets to review.
An asset without any label, or that cannot move on yet — its step is not done, someone is
labeling it — is reported under declined rather than silently left out.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset_ids |
Optional[list[str]] |
The asset internal IDs to add to review. |
None |
external_ids |
Optional[list[str]] |
The asset external IDs to add to review. |
None |
project_id |
Optional[str] |
The project ID. Only required if |
None |
Returns:
| Type | Description |
|---|---|
A dictionary with three keys, each a list covering every asset given |
|
Examples:
>>> kili.add_to_review(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def add_to_review(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Add assets to review.
An asset without any label, or that cannot move on yet — its step is not done, someone is
labeling it — is reported under `declined` rather than silently left out.
Args:
asset_ids: The asset internal IDs to add to review.
external_ids: The asset external IDs to add to review.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.add_to_review(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"add_to_review", "asset_ids", asset_ids
) or is_empty_list_with_warning("add_to_review", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(
self.graphql_client, GQL_ADD_ASSETS_TO_REVIEW, resolved_asset_ids
)
append_many_to_dataset(self, project_id, content_array=None, multi_layer_content_array=None, external_id_array=None, id_array=None, is_honeypot_array=None, status_array=None, json_content_array=None, json_metadata_array=None, disable_tqdm=None, wait_until_availability=True, from_csv=None, csv_separator=',')
Append assets to a project.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id |
str |
Identifier of the project |
required |
content_array |
Union[list[str], list[dict], list[list[dict]]] |
List of elements added to the assets of the project Must not be None except if you provide multi_layer_content_array or json_content_array.
|
None |
multi_layer_content_array |
Optional[list[list[dict]]] |
List containing multiple lists of paths.
Each path correspond to a layer of a geospatial asset. Should be used only for |
None |
external_id_array |
Optional[list[str]] |
List of external ids given to identify the assets. If None, random identifiers are created. |
None |
id_array |
Optional[list[str]] |
Disabled parameter. Do not use. |
None |
is_honeypot_array |
Optional[list[bool]] |
Whether to use the asset for honeypot |
None |
status_array |
Optional[list[str]] |
DEPRECATED and does not have any effect. |
None |
json_content_array |
Optional[list[Optional[list[Union[dict, str]]]]] |
Useful for
|
None |
json_metadata_array |
Optional[list[dict]] |
The metadata given to each asset should be stored in a json like dict with keys.
|
None |
disable_tqdm |
Optional[bool] |
If |
None |
wait_until_availability |
bool |
If |
True |
from_csv |
Optional[str] |
Path to a csv file containing the text assets to import.
Only used for |
None |
csv_separator |
str |
Separator used in the csv file. Only used if |
',' |
Returns:
| Type | Description |
|---|---|
A dictionary with two fields |
|
Examples:
>>> kili.append_many_to_dataset(
project_id=project_id,
content_array=['https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'])
Recipe
- For more detailed examples on how to import assets, see the recipe.
- For more detailed examples on how to import text assets, see the recipe.
Source code in kili/entrypoints/mutations/asset/__init__.py
def append_many_to_dataset(
self,
project_id: str,
content_array: Optional[Union[list[str], list[dict], list[list[dict]]]] = None,
multi_layer_content_array: Optional[list[list[dict]]] = None,
external_id_array: Optional[list[str]] = None,
id_array: Optional[list[str]] = None,
is_honeypot_array: Optional[list[bool]] = None,
status_array: Optional[list[str]] = None,
json_content_array: Optional[list[Union[list[Union[dict, str]], None]]] = None,
json_metadata_array: Optional[list[dict]] = None,
disable_tqdm: Optional[bool] = None,
wait_until_availability: bool = True,
from_csv: Optional[str] = None,
csv_separator: str = ",",
) -> dict[Literal["id", "asset_ids"], Union[str, list[str]]]:
# pylint: disable=line-too-long
"""Append assets to a project.
Args:
project_id: Identifier of the project
content_array: List of elements added to the assets of the project
Must not be None except if you provide multi_layer_content_array or json_content_array.
- For a `TEXT` project, the content can be either raw text, or URLs to TEXT assets.
- For an `IMAGE` / `PDF` project, the content can be either URLs or paths to existing
images/pdf on your computer.
- For a VIDEO project, the content can be either URLs pointing to videos hosted on a web server or paths to
existing video files on your computer. If you want to import video from frames, look at the json_content
section below.
- For an `VIDEO_LEGACY` project, the content can be only be URLs.
- For an `LLM_RLHF` project, the content can be dicts with the keys `prompt` and `completions`,
paths to local json files or URLs to json files.
multi_layer_content_array: List containing multiple lists of paths.
Each path correspond to a layer of a geospatial asset. Should be used only for `IMAGE` and `GEOSPATIAL` projects.
external_id_array: List of external ids given to identify the assets.
If None, random identifiers are created.
id_array: Disabled parameter. Do not use.
is_honeypot_array: Whether to use the asset for honeypot
status_array: DEPRECATED and does not have any effect.
json_content_array: Useful for `VIDEO` or `TEXT` or `IMAGE` projects only.
- For `VIDEO` projects, each element is a sequence of frames, i.e. a
list of URLs to images or a list of paths to images.
- For `TEXT` projects, each element is a json_content dict,
formatted according to documentation [on how to import
rich-text assets](https://python-sdk-docs.kili-technology.com/latest/sdk/tutorials/import_text_assets/).
- For `IMAGES` projects, it is used for satellite imagery each element is a list of json_content dicts
formatted according to documentation [on how to add multi-layer images]
(https://docs.kili-technology.com/docs/adding-assets-to-project#adding-multi-layer-images)
json_metadata_array: The metadata given to each asset should be stored in a json like dict with keys.
- Add metadata visible on the asset
Example for one asset: `json_metadata_array = [{'imageUrl': '','text': '','url': '','key1': 'value1'}]`.
- For VIDEO projects (and not VIDEO_LEGACY), you can specify a value with key 'processingParameters' to specify the sampling rate (default: 30).
Example for one asset: `json_metadata_array = [{'processingParameters': {'framesPlayedPerSecond': 10}}]`.
- In Image projects with geoTIFF assets, you can specify the epsg, the `minZoom` and `maxZoom` values for the `processingParameters` key.
- The epsg is a number that defines the projection that will be used for the asset. Values that can be used are either 4326 or 3857, the 2
projections that we support. If this number is not set, by default we keep the initial projection of the asset if it is 4326 or 3857, either
we reproject the asset to EPSG:3857 by default.
- The `minZoom` parameter defines the zoom level that users are not allowed to zoom out from. It also affects the zoom levels for which we
generate the tiles when tiling the asset (for asset with size > 30MB).
- The `maxZoom` value affects asset generation: the higher the value, the greater the level of details and the size of the asset. It also affects
the zoom levels for which we generate the tiles when tiling the asset (for asset with size > 30MB).
- Example for one asset: `json_metadata_array = [{'processingParameters': {'epsg': 3758, 'minZoom': 17, 'maxZoom': 19}}]`.
disable_tqdm: If `True`, the progress bar will be disabled
wait_until_availability: If `True`, the function will return once the assets are fully imported in Kili.
If `False`, the function will return faster but the assets might not be fully processed by the server.
from_csv: Path to a csv file containing the text assets to import.
Only used for `TEXT` projects.
If provided, `content_array` and `external_id_array` must be None.
The csv file header must specify the columns `content` and `externalId`.
csv_separator: Separator used in the csv file. Only used if `from_csv` is provided.
Returns:
A dictionary with two fields: `id` which is the project id and `asset_ids` which is a list of the created asset ids.
In the case where assets are uploaded asynchronously (for video imported as frames or big images or tiff images), the method return an empty list of asset ids.
Examples:
>>> kili.append_many_to_dataset(
project_id=project_id,
content_array=['https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'])
!!! example "Recipe"
- For more detailed examples on how to import assets,
see [the recipe](https://docs.kili-technology.com/recipes/importing-data).
- For more detailed examples on how to import text assets,
see [the recipe](https://python-sdk-docs.kili-technology.com/latest/sdk/tutorials/import_text_assets/).
"""
if from_csv is not None:
if content_array is not None or external_id_array is not None:
raise ValueError(
"If from_csv is provided, content_array and external_id_array must not be"
" provided."
)
content_array, external_id_array = get_text_assets_from_csv(
from_csv=from_csv, csv_separator=csv_separator
)
if (
is_empty_list_with_warning("append_many_to_dataset", "content_array", content_array)
or is_empty_list_with_warning(
"append_many_to_dataset", "json_content_array", json_content_array
)
or is_empty_list_with_warning(
"append_many_to_dataset", "multi_layer_content_array", multi_layer_content_array
)
):
return {"id": project_id, "asset_ids": []}
if status_array is not None:
warnings.warn(
"status_array is deprecated and will not be sent in the call. Asset status is"
" automatically computed based on its labels and cannot be overwritten.",
DeprecationWarning,
stacklevel=1,
)
if (
content_array is None
and multi_layer_content_array is None
and json_content_array is None
):
raise ValueError(
"Variables content_array, multi_layer_content_array and json_content_array cannot be both None."
)
if content_array is not None and multi_layer_content_array is not None:
raise ValueError(
"Variables content_array and multi_layer_content_array cannot be both provided."
)
nb_data = (
len(content_array)
if content_array is not None
else (
len(multi_layer_content_array)
if multi_layer_content_array is not None
else len(json_content_array) # type:ignore
)
)
field_mapping = {
"content": content_array,
"multi_layer_content": multi_layer_content_array,
"json_content": json_content_array,
"external_id": external_id_array,
"id": id_array,
"json_metadata": json_metadata_array,
"is_honeypot": is_honeypot_array,
}
assets = [{}] * nb_data
for key, value in field_mapping.items():
if value is not None:
assets = [{**assets[i], key: value[i]} for i in range(nb_data)]
created_asset_ids = import_assets(
self, # pyright: ignore[reportArgumentType]
project_id=ProjectId(project_id),
assets=assets,
disable_tqdm=disable_tqdm,
verify=wait_until_availability,
)
return {"id": project_id, "asset_ids": created_asset_ids}
assign_assets_to_labelers(self, to_be_labeled_by_array, asset_ids=None, external_ids=None, project_id=None)
Assign a list of assets to a list of labelers.
Assigning an asset to nobody unassigns it. A labeler who has a label in progress on an
asset stays assigned to it whatever this asks for: unassigning them would leave them with
an interface they can no longer submit from, and the asset in progress with nobody to
finish it. Those assets are reported under declined rather than silently left out.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset_ids |
Optional[list[str]] |
The internal asset IDs to assign. |
None |
external_ids |
Optional[list[str]] |
The external asset IDs to assign (if |
None |
project_id |
Optional[str] |
The project ID. Only required if |
None |
to_be_labeled_by_array |
list |
The array of list of labelers to assign per labelers (list of userIds). |
required |
Returns:
| Type | Description |
|---|---|
A dictionary with three keys, each a list covering every asset given |
|
Examples:
>>> kili.assign_assets_to_labelers(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
to_be_labeled_by_array=[['cm3yja6kv0i698697gcil9rtk','cm3yja6kv0i000000gcil9rtk'],
['cm3yja6kv0i698697gcil9rtk']]
)
# The following call resets the assignees on the asset_ids given.
>>> kili.assign_assets_to_labelers(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
to_be_labeled_by_array=[[], []]
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def assign_assets_to_labelers(
self,
to_be_labeled_by_array: list[list[str]],
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Assign a list of assets to a list of labelers.
Assigning an asset to nobody unassigns it. A labeler who has a label in progress on an
asset stays assigned to it whatever this asks for: unassigning them would leave them with
an interface they can no longer submit from, and the asset in progress with nobody to
finish it. Those assets are reported under `declined` rather than silently left out.
Args:
asset_ids: The internal asset IDs to assign.
external_ids: The external asset IDs to assign (if `asset_ids` is not already provided).
project_id: The project ID. Only required if `external_ids` argument is provided.
to_be_labeled_by_array: The array of list of labelers to assign per labelers (list of userIds).
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.assign_assets_to_labelers(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
to_be_labeled_by_array=[['cm3yja6kv0i698697gcil9rtk','cm3yja6kv0i000000gcil9rtk'],
['cm3yja6kv0i698697gcil9rtk']]
)
# The following call resets the assignees on the asset_ids given.
>>> kili.assign_assets_to_labelers(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
to_be_labeled_by_array=[[], []]
)
"""
if is_empty_list_with_warning(
"assign_assets_to_labelers", "asset_ids", asset_ids
) and is_empty_list_with_warning("assign_assets_to_labelers", "external_ids", external_ids):
return empty_asset_action_outcome()
if (asset_ids is not None and external_ids is not None) or (
asset_ids is None and external_ids is None
):
raise MissingArgumentError("Please provide either `asset_ids` or `external_ids`.")
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
if len(resolved_asset_ids) != len(to_be_labeled_by_array):
raise MutationError("There must be as many assets as there are lists of labelers.")
# Group assets by assignee list to batch
# assignee combination instead of 1 call per asset.
groups: dict[tuple, list[str]] = {}
for asset_id, to_be_labeled_by in zip(
resolved_asset_ids, to_be_labeled_by_array, strict=False
):
key = tuple(to_be_labeled_by)
if key not in groups:
groups[key] = []
groups[key].append(asset_id)
outcome = empty_asset_action_outcome()
for user_ids_tuple, ids_for_group in groups.items():
group_outcome = execute_asset_action(
self.graphql_client,
GQL_ASSIGN_ASSETS,
ids_for_group,
{"userIds": list(user_ids_tuple)},
)
outcome["declined"].extend(group_outcome["declined"])
outcome["failed"].extend(group_outcome["failed"])
outcome["succeeded"].extend(group_outcome["succeeded"])
return outcome
change_asset_external_ids(self, new_external_ids, asset_ids=None, external_ids=None, project_id=None)
Update the external IDs of one or more assets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
new_external_ids |
list |
The new external IDs of the assets. |
required |
asset_ids |
Optional[list[str]] |
The asset IDs to modify. |
None |
external_ids |
Optional[list[str]] |
The external asset IDs to modify (if |
None |
project_id |
Optional[str] |
The project ID. Only required if |
None |
Returns:
| Type | Description |
|---|---|
list |
A list of dictionaries with the asset ids. |
Examples:
>>> kili.change_asset_external_ids(
new_external_ids=["asset1", "asset2"],
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def change_asset_external_ids(
self,
new_external_ids: list[str],
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> list[dict[Literal["id"], str]]:
"""Update the external IDs of one or more assets.
Args:
new_external_ids: The new external IDs of the assets.
asset_ids: The asset IDs to modify.
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A list of dictionaries with the asset ids.
Examples:
>>> kili.change_asset_external_ids(
new_external_ids=["asset1", "asset2"],
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
)
"""
if is_empty_list_with_warning(
"change_asset_external_ids", "new_external_ids", new_external_ids
):
return []
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
properties_to_batch = process_update_properties_in_assets_parameters(
asset_ids=cast(list[str], resolved_asset_ids),
external_ids=new_external_ids,
)
def generate_variables(batch: dict) -> dict:
asset_ids = batch.pop("assetId")
data_array = [
dict(zip(batch, t, strict=False)) for t in zip(*batch.values(), strict=False)
] # type: ignore
return {
"whereArray": [{"id": asset_id} for asset_id in asset_ids],
"dataArray": data_array,
}
results = mutate_from_paginated_call(
self,
properties_to_batch,
generate_variables,
GQL_UPDATE_PROPERTIES_IN_ASSETS,
)
formated_results = [self.format_result("data", result, None) for result in results]
return [item for batch_list in formated_results for item in batch_list]
delete_many_from_dataset(self, asset_ids=None, external_ids=None, project_id=None)
Delete assets from a project.
A batch whose write failed is reported under failed rather than failing the call. An asset
already deleted, given by its id, is reported under succeeded: it is in the state that was
asked for.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset_ids |
Optional[list[str]] |
The list of asset internal IDs to delete. |
None |
external_ids |
Optional[list[str]] |
The list of asset external IDs to delete. |
None |
project_id |
Optional[str] |
The project ID. Only required if |
None |
Returns:
| Type | Description |
|---|---|
A dictionary with three keys, each a list covering every asset given |
|
Examples:
>>> kili.delete_many_from_dataset(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def delete_many_from_dataset(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Delete assets from a project.
A batch whose write failed is reported under `failed` rather than failing the call. An asset
already deleted, given by its id, is reported under `succeeded`: it is in the state that was
asked for.
Args:
asset_ids: The list of asset internal IDs to delete.
external_ids: The list of asset external IDs to delete.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.delete_many_from_dataset(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"delete_many_from_dataset", "asset_ids", asset_ids
) or is_empty_list_with_warning("delete_many_from_dataset", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(self.graphql_client, GQL_DELETE_ASSETS, resolved_asset_ids)
remove_metadata(self, keys, project_id, asset_ids=None, external_ids=None)
Remove metadata keys from assets, keeping their other keys.
A stored ocrMetadata key is the asset's OCR, not metadata: it is left out, and the OCR is
unchanged. The metadata is read, then written whole: two calls at once on the same asset may
lose the keys of one of them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
keys |
list |
The metadata keys to remove from each asset. A key an asset does not have is ignored. |
required |
project_id |
str |
The project ID. |
required |
asset_ids |
Optional[list[str]] |
The asset IDs to modify (if |
None |
external_ids |
Optional[list[str]] |
The external asset IDs to modify (if |
None |
Returns:
| Type | Description |
|---|---|
list |
A list of dictionaries with the asset ids. |
Exceptions:
| Type | Description |
|---|---|
ValueError |
If |
MissingArgumentError |
If both or neither of |
NotFound |
If an asset ID or an external ID matches no asset of the project, or an external ID several. |
Examples:
>>> kili.remove_metadata(
keys=["reviewed_by", "split"],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.remove_metadata(
keys=["reviewed_by"],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def remove_metadata(
self,
keys: list[str],
project_id: str,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
) -> list[dict[Literal["id"], str]]:
"""Remove metadata keys from assets, keeping their other keys.
A stored `ocrMetadata` key is the asset's OCR, not metadata: it is left out, and the OCR is
unchanged. The metadata is read, then written whole: two calls at once on the same asset may
lose the keys of one of them.
Args:
keys: The metadata keys to remove from each asset. A key an asset does not have is
ignored.
project_id: The project ID.
asset_ids: The asset IDs to modify (if `external_ids` is not already provided).
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
They are matched exactly.
Returns:
A list of dictionaries with the asset ids.
Raises:
ValueError: If `keys` holds `processingParameters`, which Kili keeps to process the
asset: change it with `add_metadata`, which keeps the asset's other metadata.
MissingArgumentError: If both or neither of `asset_ids` and `external_ids` are given.
NotFound: If an asset ID or an external ID matches no asset of the project, or an
external ID several.
Examples:
>>> kili.remove_metadata(
keys=["reviewed_by", "split"],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.remove_metadata(
keys=["reviewed_by"],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
"""
if (
is_empty_list_with_warning("remove_metadata", "keys", keys)
or is_empty_list_with_warning("remove_metadata", "asset_ids", asset_ids)
or is_empty_list_with_warning("remove_metadata", "external_ids", external_ids)
):
return []
if "processingParameters" in keys:
raise ValueError(
"`processingParameters` cannot be removed: Kili keeps it to process the asset."
' Change it with `add_metadata(json_metadata=[{"processingParameters": {...}}], ...)`,'
" which keeps the asset's other metadata."
)
asset_ids_in_order, current_metadata = AssetUseCasesUtils(
self.kili_api_gateway
).get_metadata_targets(ProjectId(project_id), asset_ids, external_ids)
new_metadata = {
asset_id: {
key: value for key, value in current_metadata[asset_id].items() if key not in keys
}
for asset_id in asset_ids_in_order
}
return self.update_properties_in_assets(
asset_ids=list(new_metadata),
json_metadatas=list(new_metadata.values()),
)
send_back_to_queue(self, asset_ids=None, external_ids=None, project_id=None)
Send assets back to queue.
An asset the send back does not apply to — one still to be labeled, or, in the multi-step
and multi-group workflows, one skipped — comes back under declined, and one whose write
failed under failed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset_ids |
Optional[list[str]] |
List of internal IDs of assets to send back to queue. |
None |
external_ids |
Optional[list[str]] |
List of external IDs of assets to send back to queue. |
None |
project_id |
Optional[str] |
The project ID. Only required if |
None |
Returns:
| Type | Description |
|---|---|
A dictionary with three keys, each a list covering every asset given |
|
Examples:
>>> kili.send_back_to_queue(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def send_back_to_queue(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Send assets back to queue.
An asset the send back does not apply to — one still to be labeled, or, in the multi-step
and multi-group workflows, one skipped — comes back under `declined`, and one whose write
failed under `failed`.
Args:
asset_ids: List of internal IDs of assets to send back to queue.
external_ids: List of external IDs of assets to send back to queue.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.send_back_to_queue(
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"send_back_to_queue", "asset_ids", asset_ids
) or is_empty_list_with_warning("send_back_to_queue", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(
self.graphql_client, GQL_SEND_ASSETS_BACK_TO_QUEUE, resolved_asset_ids
)
set_assets_priority(self, priority, asset_ids=None, external_ids=None, project_id=None)
Set the priority of assets.
An asset whose current step is not waiting for work — in progress, done or skipped — is
reported under declined rather than silently left out.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
priority |
int |
The priority to give every asset. By default, all assets have a priority of 0. |
required |
asset_ids |
Optional[list[str]] |
The internal IDs of the assets to prioritize. |
None |
external_ids |
Optional[list[str]] |
The external IDs of the assets to prioritize. |
None |
project_id |
Optional[str] |
The project ID. Only required if |
None |
Returns:
| Type | Description |
|---|---|
A dictionary with three keys, each a list covering every asset given |
|
Examples:
>>> kili.set_assets_priority(
priority=2,
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def set_assets_priority(
self,
priority: int,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
project_id: Optional[str] = None,
) -> AssetActionOutcome:
"""Set the priority of assets.
An asset whose current step is not waiting for work — in progress, done or skipped — is
reported under `declined` rather than silently left out.
Args:
priority: The priority to give every asset. By default, all assets have a priority of 0.
asset_ids: The internal IDs of the assets to prioritize.
external_ids: The external IDs of the assets to prioritize.
project_id: The project ID. Only required if `external_ids` argument is provided.
Returns:
A dictionary with three keys, each a list covering every asset given:
- `succeeded`: the assets that ended up in the state that was asked for, as
`{"assetId": ..., "externalId": ...}`.
- `declined`: the assets the request could not be applied to, as
`{"assetId": ..., "externalId": ...}`. Why is not carried: the reasons read as noise
next to the count, so no surface reports them.
- `failed`: the assets whose write threw, as
`{"assetId": ..., "externalId": ..., "details": ...}`. Unlike a declined asset, these
are worth retrying as is.
Examples:
>>> kili.set_assets_priority(
priority=2,
asset_ids=[
"ckg22d81r0jrg0885unmuswj8",
"ckg22d81s0jrh0885pdxfd03n",
],
)
"""
if is_empty_list_with_warning(
"set_assets_priority", "asset_ids", asset_ids
) or is_empty_list_with_warning("set_assets_priority", "external_ids", external_ids):
return empty_asset_action_outcome()
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
return execute_asset_action(
self.graphql_client,
GQL_SET_ASSETS_PRIORITY,
resolved_asset_ids,
{"priority": priority},
)
set_metadata(self, json_metadata, project_id, asset_ids=None, external_ids=None)
Set metadata on assets, replacing their existing metadata.
Each dictionary replaces the metadata of the asset given at the same position, except the
keys text, imageUrl, url and processingParameters, which the asset keeps unless the
dictionary gives them. The metadata is read, then written whole: two calls at once on the
same asset may lose the keys of one of them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_metadata |
list |
List of metadata dictionaries to set on each asset, one per asset, in
the order of |
required |
project_id |
str |
The project ID. |
required |
asset_ids |
Optional[list[str]] |
The asset IDs to modify (if |
None |
external_ids |
Optional[list[str]] |
The external asset IDs to modify (if |
None |
Returns:
| Type | Description |
|---|---|
list |
A list of dictionaries with the asset ids. |
Exceptions:
| Type | Description |
|---|---|
MissingArgumentError |
If both or neither of |
IncompatibleArgumentsError |
If |
NotFound |
If an asset ID or an external ID matches no asset of the project, or an external ID several. |
Examples:
>>> kili.set_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.set_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def set_metadata(
self,
json_metadata: list[dict[str, Any]],
project_id: str,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
) -> list[dict[Literal["id"], str]]:
"""Set metadata on assets, replacing their existing metadata.
Each dictionary replaces the metadata of the asset given at the same position, except the
keys `text`, `imageUrl`, `url` and `processingParameters`, which the asset keeps unless the
dictionary gives them. The metadata is read, then written whole: two calls at once on the
same asset may lose the keys of one of them.
Args:
json_metadata: List of metadata dictionaries to set on each asset, one per asset, in
the order of `asset_ids` or `external_ids`. Values can be nested dicts and lists.
project_id: The project ID.
asset_ids: The asset IDs to modify (if `external_ids` is not already provided).
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
They are matched exactly.
Returns:
A list of dictionaries with the asset ids.
Raises:
MissingArgumentError: If both or neither of `asset_ids` and `external_ids` are given.
IncompatibleArgumentsError: If `json_metadata` and the ids do not have the same length.
NotFound: If an asset ID or an external ID matches no asset of the project, or an
external ID several.
Examples:
>>> kili.set_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"]
)
# Or using external IDs
>>> kili.set_metadata(
json_metadata=[
{"key1": "value1", "key2": "value2"},
{"key3": "value3"}
],
project_id="cm92to3cx012u7l0w6kij9qvx",
external_ids=["asset1", "asset2"]
)
"""
if is_empty_list_with_warning("set_metadata", "json_metadata", json_metadata):
return []
asset_ids_in_order, current_metadata = AssetUseCasesUtils(
self.kili_api_gateway
).get_metadata_targets(ProjectId(project_id), asset_ids, external_ids, len(json_metadata))
# an asset given twice gets both dictionaries in turn, as two calls would
new_metadata: dict[str, dict] = {}
for asset_id, metadata in zip(asset_ids_in_order, json_metadata, strict=True):
kept_metadata = {
key: value
for key, value in new_metadata.get(asset_id, current_metadata[asset_id]).items()
if key in METADATA_KEYS_KEPT_BY_SET
}
new_metadata[asset_id] = {**kept_metadata, **metadata}
return self.update_properties_in_assets(
asset_ids=list(new_metadata),
json_metadatas=list(new_metadata.values()),
)
skip_or_unskip(self, action, asset_id, project_id, reason=None)
Skip or unskip an asset.
An asset used for consensus cannot be skipped: skipping it would remove the asset from the queue for every labeler assigned to it, not just the one requesting the skip.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action |
Literal['skip', 'unskip'] |
The action you want to do. Either skip or unskip. |
required |
asset_id |
str |
ID of the asset you want to skip or unskip. |
required |
project_id |
str |
The project ID. |
required |
reason |
Optional[str] |
The reason why you skip an asset. Only required if the action is |
None |
Returns:
| Type | Description |
|---|---|
str |
The asset ID of the asset modified. An error message if mutation failed. |
Examples:
>>> kili.skip_or_unskip(
action="skip",
asset_id="ckg22d81s0jrh0885pdxfd03n",
project_id="ckg22d81r0jrg0885unmuswj8",
reason="Test"
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def skip_or_unskip(
self,
action: Literal["skip", "unskip"],
asset_id: str,
project_id: str,
reason: Optional[str] = None,
) -> str:
"""Skip or unskip an asset.
An asset used for consensus cannot be skipped: skipping it would remove the asset from
the queue for every labeler assigned to it, not just the one requesting the skip.
Args:
action: The action you want to do. Either skip or unskip.
asset_id: ID of the asset you want to skip or unskip.
project_id: The project ID.
reason: The reason why you skip an asset. Only required if the action is `skip`.
Returns:
The asset ID of the asset modified. An error message if mutation failed.
Examples:
>>> kili.skip_or_unskip(
action="skip",
asset_id="ckg22d81s0jrh0885pdxfd03n",
project_id="ckg22d81r0jrg0885unmuswj8",
reason="Test"
)
"""
if action == "skip":
if reason is None:
raise MissingArgumentError("You must provide a reason to skip an asset")
payload = {"reason": reason, "where": {"id": asset_id, "project": {"id": project_id}}}
self.graphql_client.execute(GQL_SKIP_ASSET, payload)
else:
payload = {"projectId": project_id, "assetId": asset_id}
self.graphql_client.execute(GQL_UNSKIP_ASSET, payload)
return asset_id
update_properties_in_assets(self, asset_ids=None, external_ids=None, priorities=None, json_metadatas=None, consensus_marks=None, honeypot_marks=None, to_be_labeled_by_array=None, contents=None, json_contents=None, status_array=None, is_used_for_consensus_array=None, is_honeypot_array=None, project_id=None, resolution_array=None, page_resolutions_array=None)
Update the properties of one or more assets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset_ids |
Optional[list[str]] |
The internal asset IDs to modify. |
None |
external_ids |
Optional[list[str]] |
The external asset IDs to modify (if |
None |
priorities |
Optional[list[int]] |
DEPRECATED, use |
None |
json_metadatas |
Optional[list[Union[dict, str]]] |
The metadata given to an asset should be stored
in a json like dict with keys |
None |
consensus_marks |
Optional[list[float]] |
Should be between 0 and 1. |
None |
honeypot_marks |
Optional[list[float]] |
Should be between 0 and 1. |
None |
to_be_labeled_by_array |
Optional[list[list[str]]] |
If given, each element of the list should contain the emails of the labelers authorized to label the asset. |
None |
contents |
Optional[list[str]] |
|
None |
json_contents |
Optional[list[str]] |
|
None |
status_array |
Optional[list[str]] |
DEPRECATED and does not have any effect. |
None |
is_used_for_consensus_array |
Optional[list[bool]] |
Whether to use the asset to compute consensus kpis or not.
Only supported in the legacy workflow; in the multi-step and multi-group workflows it
raises |
None |
is_honeypot_array |
Optional[list[bool]] |
Whether to use the asset for honeypot. |
None |
project_id |
Optional[str] |
The project ID. Only required if |
None |
resolution_array |
Optional[list[dict]] |
The resolution of each asset (for image and video assets).
Each resolution must be passed as a dictionary with keys |
None |
page_resolutions_array |
Union[list[list[dict]], list[list[kili.utils.assets.PageResolution]]] |
The resolution of each page of the asset (for PDF assets).
Note that each element of the array should contain all the pages resolutions of the
corresponding asset. Each resolution can be passed as a
|
None |
Returns:
| Type | Description |
|---|---|
list |
A list of dictionaries with the asset ids. |
Exceptions:
| Type | Description |
|---|---|
DeprecatedArgumentError |
If |
MissingArgumentError |
If both |
GraphQLError |
If the backend refuses the update for any other reason. |
Examples:
>>> kili.update_properties_in_assets(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
consensus_marks=[1, 0.7],
contents=[None, 'https://to/second/asset.png'],
honeypot_marks=[0.8, 0.5],
is_honeypot_array=[True, True],
is_used_for_consensus_array=[True, False],
to_be_labeled_by_array=[['test+pierre@kili-technology.com'], None],
)
# The following call updates the pages resolutions of PDF assets.
>>> kili.update_properties_in_assets(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
page_resolutions_array=[
[
PageResolution(width=480, height=640, page_number=1),
PageResolution(width=480, height=640, page_number=2),
],[
PageResolution(width=340, height=512, page_number=1),
PageResolution(width=680, height=1024, page_number=2, rotation=90),
PageResolution(width=680, height=1024, page_number=3),
]
],
)
Source code in kili/entrypoints/mutations/asset/__init__.py
def update_properties_in_assets(
self,
asset_ids: Optional[list[str]] = None,
external_ids: Optional[list[str]] = None,
priorities: Optional[list[int]] = None,
json_metadatas: Optional[list[Union[dict, str]]] = None,
consensus_marks: Optional[list[float]] = None,
honeypot_marks: Optional[list[float]] = None,
to_be_labeled_by_array: Optional[list[list[str]]] = None,
contents: Optional[list[str]] = None,
json_contents: Optional[list[str]] = None,
status_array: Optional[list[str]] = None,
is_used_for_consensus_array: Optional[list[bool]] = None,
is_honeypot_array: Optional[list[bool]] = None,
project_id: Optional[str] = None,
resolution_array: Optional[list[dict]] = None,
page_resolutions_array: Optional[
Union[list[list[dict]], list[list[PageResolution]]]
] = None,
) -> list[dict[Literal["id"], str]]:
"""Update the properties of one or more assets.
Args:
asset_ids: The internal asset IDs to modify.
external_ids: The external asset IDs to modify (if `asset_ids` is not already provided).
priorities: DEPRECATED, use `kili.set_assets_priority()` instead, which reports the
assets it could not be applied to. You can change the priority of the assets.
By default, all assets have a priority of 0.
json_metadatas: The metadata given to an asset should be stored
in a json like dict with keys `imageUrl`, `text`, `url`:
`json_metadata = {'imageUrl': '','text': '','url': ''}`
consensus_marks: Should be between 0 and 1.
honeypot_marks: Should be between 0 and 1.
to_be_labeled_by_array: If given, each element of the list should contain the emails of
the labelers authorized to label the asset.
contents: - For a NLP project, the content can be directly in text format.
- For an Image / Video / Pdf project, the content must be hosted on a web server,
and you point Kili to your data by giving the URLs.
json_contents: - For a NLP project, the `json_content`
is a text formatted using RichText.
- For a Video project, the`json_content` is a json containg urls pointing
to each frame of the video.
status_array: DEPRECATED and does not have any effect.
is_used_for_consensus_array: Whether to use the asset to compute consensus kpis or not.
Only supported in the legacy workflow; in the multi-step and multi-group workflows it
raises `DeprecatedArgumentError`, use `kili.update_asset_consensus()` instead.
is_honeypot_array: Whether to use the asset for honeypot.
project_id: The project ID. Only required if `external_ids` argument is provided.
resolution_array: The resolution of each asset (for image and video assets).
Each resolution must be passed as a dictionary with keys `width` and `height`.
page_resolutions_array: The resolution of each page of the asset (for PDF assets).
Note that each element of the array should contain all the pages resolutions of the
corresponding asset. Each resolution can be passed as a
`kili.utils.assets.PageResolution` object, or as a dictionary with keys `width`,
`height`, `pageNumber` and optionally `rotation`.
Returns:
A list of dictionaries with the asset ids.
Raises:
DeprecatedArgumentError: If `is_used_for_consensus_array` is used on a multi-step or
multi-group workflow project. Use `kili.update_asset_consensus()` for those
projects.
MissingArgumentError: If both `asset_ids` and `external_ids` are provided, or if
neither of them is.
GraphQLError: If the backend refuses the update for any other reason.
Examples:
>>> kili.update_properties_in_assets(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
consensus_marks=[1, 0.7],
contents=[None, 'https://to/second/asset.png'],
honeypot_marks=[0.8, 0.5],
is_honeypot_array=[True, True],
is_used_for_consensus_array=[True, False],
to_be_labeled_by_array=[['test+pierre@kili-technology.com'], None],
)
# The following call updates the pages resolutions of PDF assets.
>>> kili.update_properties_in_assets(
asset_ids=["ckg22d81r0jrg0885unmuswj8", "ckg22d81s0jrh0885pdxfd03n"],
page_resolutions_array=[
[
PageResolution(width=480, height=640, page_number=1),
PageResolution(width=480, height=640, page_number=2),
],[
PageResolution(width=340, height=512, page_number=1),
PageResolution(width=680, height=1024, page_number=2, rotation=90),
PageResolution(width=680, height=1024, page_number=3),
]
],
)
"""
if is_empty_list_with_warning(
"update_properties_in_assets", "asset_ids", asset_ids
) or is_empty_list_with_warning(
"update_properties_in_assets", "external_ids", external_ids
):
return []
if status_array is not None:
warnings.warn(
"status_array is deprecated and will not be sent in the call. Asset status is"
" automatically computed based on its labels and cannot be overwritten.",
DeprecationWarning,
stacklevel=1,
)
if asset_ids is not None and external_ids is not None:
warnings.warn(
"The use of `external_ids` argument has changed. It is now used to identify"
" which properties of which assets to update. Please use"
" `kili.change_asset_external_ids()` method instead to change asset external"
" IDs.",
DeprecationWarning,
stacklevel=1,
)
raise MissingArgumentError("Please provide either `asset_ids` or `external_ids`.")
if to_be_labeled_by_array is not None:
warnings.warn(
"to_be_labeled_by_array is going to be deprecated. Please use"
" `kili.assign_assets_to_labelers()` method instead to assign assets",
DeprecationWarning,
stacklevel=1,
)
if priorities is not None:
warnings.warn(
"priorities is deprecated: it does not report the assets it could not be applied"
" to. Please use `kili.set_assets_priority()` method instead to prioritize assets",
DeprecationWarning,
stacklevel=1,
)
resolved_asset_ids = self._resolve_asset_ids(asset_ids, external_ids, project_id)
properties_to_batch = process_update_properties_in_assets_parameters(
cast(list[str], resolved_asset_ids),
priorities=priorities,
json_metadatas=json_metadatas,
consensus_marks=consensus_marks,
honeypot_marks=honeypot_marks,
to_be_labeled_by_array=to_be_labeled_by_array,
contents=contents,
json_contents=json_contents,
is_used_for_consensus_array=is_used_for_consensus_array,
is_honeypot_array=is_honeypot_array,
resolution_array=resolution_array,
page_resolutions_array=page_resolutions_array,
)
def generate_variables(batch: dict) -> dict:
asset_ids = batch.pop("assetId")
data_array = [
dict(zip(batch, t, strict=False)) for t in zip(*batch.values(), strict=False)
] # type: ignore
return {
"whereArray": [{"id": asset_id} for asset_id in asset_ids],
"dataArray": data_array,
}
try:
results = mutate_from_paginated_call(
self,
properties_to_batch,
generate_variables,
GQL_UPDATE_PROPERTIES_IN_ASSETS,
)
except GraphQLError as err:
deprecation_message = _get_error_message_with_key(err, DEPRECATED_ERROR_KEY)
if deprecation_message is not None:
raise DeprecatedArgumentError(_to_sdk_method_names(deprecation_message)) from err
raise
formated_results = [self.format_result("data", result, None) for result in results]
return [item for batch_list in formated_results for item in batch_list]