Skip to content

Commit 337d45c

Browse files
committed
feat(LAB-4081): add "is not" operator filters to Python SDK for status, step and step status
1 parent c3d9a4f commit 337d45c

File tree

5 files changed

+95
-1
lines changed

5 files changed

+95
-1
lines changed

src/kili/adapters/kili_api_gateway/asset/mappers.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def asset_where_mapper(filters: AssetFilters):
2828
"externalIdStrictlyIn": filters.external_id_strictly_in,
2929
"externalIdIn": filters.external_id_in,
3030
"statusIn": filters.status_in,
31+
"statusNotIn": filters.status_not_in,
3132
"consensusMarkGte": filters.consensus_mark_gte,
3233
"consensusMarkLte": filters.consensus_mark_lte,
3334
"honeypotMarkGte": filters.honeypot_mark_gte,
@@ -65,5 +66,7 @@ def asset_where_mapper(filters: AssetFilters):
6566
"status": filters.issue_status,
6667
},
6768
"stepIdIn": filters.step_id_in,
69+
"stepIdNotIn": filters.step_id_not_in,
6870
"stepStatusIn": filters.step_status_in,
71+
"stepStatusNotIn": filters.step_status_not_in,
6972
}

src/kili/domain/asset/asset.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,23 @@ class AssetFilters:
6262
issue_status: Optional["IssueStatus"] = None
6363
skipped: Optional[bool] = None
6464
status_in: Optional[ListOrTuple[AssetStatus]] = None
65+
status_not_in: Optional[ListOrTuple[AssetStatus]] = None
6566
step_id_in: Optional[ListOrTuple[str]] = None
67+
step_id_not_in: Optional[ListOrTuple[str]] = None
6668
step_status_in: Optional[ListOrTuple[StatusInStep]] = None
69+
step_status_not_in: Optional[ListOrTuple[StatusInStep]] = None
6770

6871

6972
class AssetWorkflowFilters(TypedDict):
7073
"""Asset filters relative to worklow."""
7174

7275
skipped: Optional[bool]
7376
status_in: Optional[ListOrTuple[AssetStatus]]
77+
status_not_in: Optional[ListOrTuple[AssetStatus]]
7478
step_name_in: Optional[ListOrTuple[str]]
79+
step_name_not_in: Optional[ListOrTuple[str]]
7580
step_status_in: Optional[ListOrTuple[StatusInStep]]
81+
step_status_not_in: Optional[ListOrTuple[StatusInStep]]
7682

7783

7884
def get_asset_default_fields(

src/kili/domain/asset/helpers.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,40 @@ def check_asset_workflow_arguments(
3434
) -> None:
3535
"""Check asset workflow parameters relative to the project workflow version."""
3636
step_name_in = asset_workflow_filters.get("step_name_in")
37+
step_name_not_in = asset_workflow_filters.get("step_name_not_in")
3738
step_status_in = asset_workflow_filters.get("step_status_in")
39+
step_status_not_in = asset_workflow_filters.get("step_status_not_in")
3840
status_in = asset_workflow_filters.get("status_in")
41+
status_not_in = asset_workflow_filters.get("status_not_in")
3942
skipped = asset_workflow_filters.get("skipped")
4043

4144
if project_workflow_version == "V2":
4245
if step_status_in is not None and status_in is not None:
4346
raise ValueError(
4447
"Filters step_status_in and status_in both given : only use filter step_status_in for this project."
4548
)
49+
if step_status_not_in is not None and status_not_in is not None:
50+
raise ValueError(
51+
"Filters step_status_not_in and status_not_in both given : only use filter step_status_not_in for this project."
52+
)
4653
if step_name_in is not None and status_in is not None:
4754
raise ValueError(
4855
"Filters step_name_in and status_in both given : use filter step_status_in instead of status_in for this project." # pylint: disable=line-too-long
4956
)
57+
if step_name_not_in is not None and status_not_in is not None:
58+
raise ValueError(
59+
"Filters step_name_not_in and status_not_in both given : use filter step_status_not_in instead of status_not_in for this project." # pylint: disable=line-too-long
60+
)
5061
if status_in is not None:
5162
warnings.warn(
5263
"Filter status_in given : use filters step_status_in and step_name_in instead for this project.",
5364
stacklevel=1,
5465
)
66+
if status_not_in is not None:
67+
warnings.warn(
68+
"Filter status_not_in given : use filters step_status_not_in and step_name_not_in instead for this project.",
69+
stacklevel=1,
70+
)
5571
if skipped is not None:
5672
warnings.warn(
5773
"Filter skipped given : only use filter step_status_in with the SKIPPED step status instead for this project", # pylint: disable=line-too-long
@@ -64,3 +80,7 @@ def check_asset_workflow_arguments(
6480
raise ValueError(
6581
"Filters step_name_in and/or step_status_in given : use filter status_in for this project."
6682
)
83+
if step_name_not_in is not None or step_status_not_in is not None:
84+
raise ValueError(
85+
"Filters step_name_not_in and/or step_status_not_in given : use filter status_not_in for this project."
86+
)

src/kili/domain_api/assets.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,11 @@ class AssetFilter(TypedDict, total=False):
8888
metadata_where: Optional[Dict[str, Any]]
8989
skipped: Optional[bool]
9090
status_in: Optional[List[AssetStatus]]
91+
status_not_in: Optional[List[AssetStatus]]
9192
step_name_in: Optional[List[str]]
93+
step_name_not_in: Optional[List[str]]
9294
step_status_in: Optional[List[StatusInStep]]
95+
step_status_not_in: Optional[List[StatusInStep]]
9396
updated_at_gte: Optional[str]
9497
updated_at_lte: Optional[str]
9598

src/kili/presentation/client/asset.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,11 @@ def assets(
110110
label_output_format: Literal["dict", "parsed_label"] = "dict",
111111
skipped: Optional[bool] = None,
112112
status_in: Optional[List[AssetStatus]] = None,
113+
status_not_in: Optional[List[AssetStatus]] = None,
113114
step_name_in: Optional[List[str]] = None,
115+
step_name_not_in: Optional[List[str]] = None,
114116
step_status_in: Optional[List[StatusInStep]] = None,
117+
step_status_not_in: Optional[List[StatusInStep]] = None,
115118
*,
116119
as_generator: Literal[True],
117120
) -> Generator[Dict, None, None]:
@@ -176,8 +179,11 @@ def assets(
176179
label_output_format: Literal["dict", "parsed_label"] = "dict",
177180
skipped: Optional[bool] = None,
178181
status_in: Optional[List[AssetStatus]] = None,
182+
status_not_in: Optional[List[AssetStatus]] = None,
179183
step_name_in: Optional[List[str]] = None,
184+
step_name_not_in: Optional[List[str]] = None,
180185
step_status_in: Optional[List[StatusInStep]] = None,
186+
step_status_not_in: Optional[List[StatusInStep]] = None,
181187
*,
182188
as_generator: Literal[False] = False,
183189
) -> List[Dict]:
@@ -242,8 +248,11 @@ def assets(
242248
label_output_format: Literal["dict", "parsed_label"] = "dict",
243249
skipped: Optional[bool] = None,
244250
status_in: Optional[List[AssetStatus]] = None,
251+
status_not_in: Optional[List[AssetStatus]] = None,
245252
step_name_in: Optional[List[str]] = None,
253+
step_name_not_in: Optional[List[str]] = None,
246254
step_status_in: Optional[List[StatusInStep]] = None,
255+
step_status_not_in: Optional[List[StatusInStep]] = None,
247256
*,
248257
as_generator: bool = False,
249258
) -> Union[Iterable[Dict], "pd.DataFrame"]:
@@ -313,10 +322,18 @@ def assets(
313322
status_in: Returned assets should have a status that belongs to that list, if given.
314323
Possible choices: `TODO`, `ONGOING`, `LABELED`, `TO_REVIEW` or `REVIEWED`.
315324
Only applicable if the project is in the WorkflowV1 (legacy).
325+
status_not_in: Returned assets should have a status that does not belong to that list, if given.
326+
Possible choices: `TODO`, `ONGOING`, `LABELED`, `TO_REVIEW` or `REVIEWED`.
327+
Only applicable if the project is in the WorkflowV1 (legacy).
316328
step_name_in: Returned assets are in the step whose name belong to that list, if given.
317329
Only applicable if the project is in WorkflowV2.
330+
step_name_not_in: Returned assets are in the step whose name does not belong to that list, if given.
331+
Only applicable if the project is in WorkflowV2.
318332
step_status_in: Returned assets have the status in their step that belongs to that list, if given.
319333
Only applicable if the project is in WorkflowV2.
334+
step_status_not_in: Returned assets have the status in their step that does not belong to that list, if given.
335+
Possible choices: `TO_DO`, `DOING`, `PARTIALLY_DONE`, `REDO`, `DONE`, `SKIPPED`.
336+
Only applicable if the project is in WorkflowV2.
320337
321338
!!! info "Dates format"
322339
Date strings should have format: "YYYY-MM-DD"
@@ -432,26 +449,38 @@ def assets(
432449
)
433450

434451
step_id_in = None
452+
step_id_not_in = None
435453
if (
436454
step_name_in is not None
455+
or step_name_not_in is not None
437456
or step_status_in is not None
457+
or step_status_not_in is not None
438458
or status_in is not None
459+
or status_not_in is not None
439460
or skipped is not None
440461
):
441462
check_asset_workflow_arguments(
442463
project_workflow_version=project_workflow_version,
443464
asset_workflow_filters={
444465
"skipped": skipped,
445466
"status_in": status_in,
467+
"status_not_in": status_not_in,
446468
"step_name_in": step_name_in,
469+
"step_name_not_in": step_name_not_in,
447470
"step_status_in": step_status_in,
471+
"step_status_not_in": step_status_not_in,
448472
},
449473
)
450474
if project_workflow_version == "V2" and step_name_in is not None:
451475
step_id_in = extract_step_ids_from_project_steps(
452476
project_steps=project_steps,
453477
step_name_in=step_name_in,
454478
)
479+
if project_workflow_version == "V2" and step_name_not_in is not None:
480+
step_id_not_in = extract_step_ids_from_project_steps(
481+
project_steps=project_steps,
482+
step_name_in=step_name_not_in,
483+
)
455484

456485
asset_use_cases = AssetUseCases(self.kili_api_gateway)
457486
filters = AssetFilters(
@@ -497,7 +526,10 @@ def assets(
497526
issue_status=issue_status,
498527
issue_type=issue_type,
499528
step_id_in=step_id_in,
529+
step_id_not_in=step_id_not_in,
500530
step_status_in=step_status_in,
531+
step_status_not_in=step_status_not_in,
532+
status_not_in=status_not_in,
501533
)
502534
assets_gen = asset_use_cases.list_assets(
503535
filters,
@@ -570,7 +602,10 @@ def count_assets(
570602
external_id_strictly_in: Optional[List[str]] = None,
571603
external_id_in: Optional[List[str]] = None,
572604
step_name_in: Optional[List[str]] = None,
605+
step_name_not_in: Optional[List[str]] = None,
573606
step_status_in: Optional[List[StatusInStep]] = None,
607+
step_status_not_in: Optional[List[StatusInStep]] = None,
608+
status_not_in: Optional[List[AssetStatus]] = None,
574609
) -> int:
575610
# pylint: disable=line-too-long
576611
"""Count and return the number of assets with the given constraints.
@@ -629,9 +664,17 @@ def count_assets(
629664
For example, with `external_id_in=['abc']`, any asset with an external id containing `'abc'` will be returned.
630665
step_name_in: Returned assets are in a step whose name belong to that list, if given.
631666
Only applicable if the project is in WorkflowV2.
667+
step_name_not_in: Returned assets are in a step whose name does not belong to that list, if given.
668+
Only applicable if the project is in WorkflowV2.
632669
step_status_in: Returned assets have the status of their step that belongs to that list, if given.
633670
Possible choices: `TO_DO`, `DOING`, `PARTIALLY_DONE`, `REDO`, `DONE`, `SKIPPED`.
634671
Only applicable if the project is in WorkflowV2.
672+
step_status_not_in: Returned assets have the status of their step that does not belong to that list, if given.
673+
Possible choices: `TO_DO`, `DOING`, `PARTIALLY_DONE`, `REDO`, `DONE`, `SKIPPED`.
674+
Only applicable if the project is in WorkflowV2.
675+
status_not_in: Returned assets should have a status that does not belong to that list, if given.
676+
Possible choices: `TODO`, `ONGOING`, `LABELED`, `TO_REVIEW` or `REVIEWED`.
677+
Only applicable if the project is in WorkflowV1 (legacy).
635678
636679
!!! info "Dates format"
637680
Date strings should have format: "YYYY-MM-DD"
@@ -695,7 +738,15 @@ def count_assets(
695738
)
696739

697740
step_id_in = None
698-
if status_in is not None or step_name_in is not None or step_status_in is not None:
741+
step_id_not_in = None
742+
if (
743+
status_in is not None
744+
or status_not_in is not None
745+
or step_name_in is not None
746+
or step_name_not_in is not None
747+
or step_status_in is not None
748+
or step_status_not_in is not None
749+
):
699750
project_use_cases = ProjectUseCases(self.kili_api_gateway)
700751
(
701752
project_steps,
@@ -706,8 +757,11 @@ def count_assets(
706757
asset_workflow_filters={
707758
"skipped": skipped,
708759
"step_name_in": step_name_in,
760+
"step_name_not_in": step_name_not_in,
709761
"step_status_in": step_status_in,
762+
"step_status_not_in": step_status_not_in,
710763
"status_in": status_in,
764+
"status_not_in": status_not_in,
711765
},
712766
)
713767

@@ -716,6 +770,11 @@ def count_assets(
716770
project_steps=project_steps,
717771
step_name_in=step_name_in,
718772
)
773+
if project_workflow_version == "V2" and step_name_not_in is not None:
774+
step_id_not_in = extract_step_ids_from_project_steps(
775+
project_steps=project_steps,
776+
step_name_in=step_name_not_in,
777+
)
719778

720779
filters = AssetFilters(
721780
project_id=ProjectId(project_id),
@@ -760,7 +819,10 @@ def count_assets(
760819
issue_status=issue_status,
761820
issue_type=issue_type,
762821
step_id_in=step_id_in,
822+
step_id_not_in=step_id_not_in,
763823
step_status_in=step_status_in,
824+
step_status_not_in=step_status_not_in,
825+
status_not_in=status_not_in,
764826
)
765827
asset_use_cases = AssetUseCases(self.kili_api_gateway)
766828
return asset_use_cases.count_assets(filters)

0 commit comments

Comments
 (0)