Skip to content

Commit 0045e5c

Browse files
author
Val Brodsky
committed
Integrate search filters with graphql
1 parent 613f01a commit 0045e5c

File tree

6 files changed

+129
-71
lines changed

6 files changed

+129
-71
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Labeling Service Status
2+
===============================================================================================
3+
4+
.. automodule:: labelbox.schema.labeling_service_status
5+
:members:
6+
:show-inheritance:

libs/labelbox/src/labelbox/schema/labeling_service_dashboard.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from labelbox.exceptions import ResourceNotFoundError
66
from labelbox.pagination import PaginatedCollection
77
from labelbox.pydantic_compat import BaseModel, root_validator, Field
8+
from labelbox.schema.search_filters import SearchFilter, build_search_filter
89
from labelbox.utils import _CamelCaseMixin
910
from labelbox.schema.labeling_service_status import LabelingServiceStatus
1011

@@ -95,22 +96,33 @@ def get_all(
9596
cls,
9697
client,
9798
after: Optional[str] = None,
98-
search_query: Optional[List[Dict]] = None,
99+
search_query: Optional[List[SearchFilter]] = None,
99100
) -> PaginatedCollection:
100-
template = Template(
101-
"""query SearchProjectsPyApi($$first: Int, $$from: String) {
102-
searchProjects(input: {after: $$from, searchQuery: $search_query, size: $$first})
103-
{
104-
nodes { $labeling_dashboard_selections }
105-
pageInfo { endCursor }
101+
102+
if search_query is not None:
103+
template = Template(
104+
"""query SearchProjectsPyApi($$first: Int, $$from: String) {
105+
searchProjects(input: {after: $$from, searchQuery: $search_query, size: $$first})
106+
{
107+
nodes { $labeling_dashboard_selections }
108+
pageInfo { endCursor }
109+
}
110+
}
111+
""")
112+
else:
113+
template = Template(
114+
"""query SearchProjectsPyApi($$first: Int, $$from: String) {
115+
searchProjects(input: {after: $$from, size: $$first})
116+
{
117+
nodes { $labeling_dashboard_selections }
118+
pageInfo { endCursor }
119+
}
106120
}
107-
}
108-
""")
109-
organization_id = client.get_organization().uid
121+
""")
110122
query_str = template.substitute(
111123
labeling_dashboard_selections=GRAPHQL_QUERY_SELECTIONS,
112-
search_query=
113-
f"[{{type: \"organization\", operator: \"is\", values: [\"{organization_id}\"]}}]"
124+
search_query=build_search_filter(search_query)
125+
if search_query else None,
114126
)
115127

116128
params: Dict[str, Union[str, int]] = {}

libs/labelbox/src/labelbox/schema/search_filters.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,24 @@ class WorkforceStageUpdatedRangeFilter(BaseSearchFilter):
107107
value: DateRangeValue
108108

109109

110-
SearchFilters = Union[OrganizationFilter, WorkspaceFilter, TagFilter,
111-
ProjectStageFilter, WorkforceRequestedDateFilter,
112-
WorkforceStageUpdatedFilter,
113-
WorkforceRequestedDateRangeFilter,
114-
WorkforceStageUpdatedRangeFilter]
115-
116-
117-
def _build_search_filter(filter: List[SearchFilters]):
118-
operation_types = {f.operation for f in filter}
119-
if len(operation_types) < len(filter):
120-
raise ValueError("Only one filter per operation type is allowed")
121-
122-
return [f.dict() for f in filter]
110+
SearchFilter = Union[OrganizationFilter, WorkspaceFilter, TagFilter,
111+
ProjectStageFilter, WorkforceRequestedDateFilter,
112+
WorkforceStageUpdatedFilter,
113+
WorkforceRequestedDateRangeFilter,
114+
WorkforceStageUpdatedRangeFilter]
115+
116+
117+
def _dict_to_graphql_string(d: Union[dict, list]) -> str:
118+
if isinstance(d, dict):
119+
return "{" + ", ".join(
120+
f'{k}: {_dict_to_graphql_string(v)}' for k, v in d.items()) + "}"
121+
elif isinstance(d, list):
122+
return "[" + ", ".join(
123+
_dict_to_graphql_string(item) for item in d) + "]"
124+
else:
125+
return f'"{d}"' if isinstance(d, str) else str(d)
126+
127+
128+
def build_search_filter(filter: List[SearchFilter]):
129+
filters = [_dict_to_graphql_string(f.dict()) for f in filter]
130+
return "[" + ", ".join(filters) + "]"

libs/labelbox/tests/conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,3 +1096,21 @@ def embedding(client: Client, environ):
10961096
@pytest.fixture
10971097
def valid_model_id():
10981098
return "2c903542-d1da-48fd-9db1-8c62571bd3d2"
1099+
1100+
1101+
@pytest.fixture
1102+
def requested_labeling_service(
1103+
rand_gen, live_chat_evaluation_project_with_new_dataset,
1104+
chat_evaluation_ontology, model_config):
1105+
project = live_chat_evaluation_project_with_new_dataset
1106+
project.connect_ontology(chat_evaluation_ontology)
1107+
1108+
project.upsert_instructions('tests/integration/media/sample_pdf.pdf')
1109+
1110+
labeling_service = project.get_labeling_service()
1111+
project.add_model_config(model_config.uid)
1112+
project.set_project_model_setup_complete()
1113+
1114+
labeling_service.request()
1115+
1116+
yield project, labeling_service

libs/labelbox/tests/integration/test_labeling_dashboard.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
from datetime import datetime, timedelta
12
from labelbox.schema.labeling_service import LabelingServiceStatus
3+
from labelbox.schema.search_filters import DateOperator, DateRange, DateRangeOperator, DateRangeValue, DateValue, IdOperator, OperationType, OrganizationFilter, WorkforceRequestedDateFilter, WorkforceRequestedDateRangeFilter, WorkspaceFilter
24

35

4-
def test_request_labeling_service_moe_offline_project(
6+
def test_request_labeling_service_dashboard(
57
rand_gen, offline_chat_evaluation_project, chat_evaluation_ontology,
68
offline_conversational_data_row):
79
project = offline_chat_evaluation_project
@@ -22,3 +24,56 @@ def test_request_labeling_service_moe_offline_project(
2224
assert labeling_service_dashboard.status == LabelingServiceStatus.Missing
2325
assert labeling_service_dashboard.tasks_completed == 0
2426
assert labeling_service_dashboard.tasks_remaining == 0
27+
28+
29+
def test_request_labeling_service_dashboard_filters(requested_labeling_service):
30+
project, _ = requested_labeling_service
31+
32+
organization = project.client.get_organization()
33+
org_filter = OrganizationFilter(
34+
operation=OperationType.Organization,
35+
operator=IdOperator.Is,
36+
values=[organization.uid])
37+
38+
labeling_service_dashboard = [
39+
ld for ld in project.client.get_labeling_service_dashboards(search_query=[org_filter])
40+
][0]
41+
assert labeling_service_dashboard is not None
42+
43+
workforce_requested_filter_before = WorkforceRequestedDateFilter(
44+
operation=OperationType.WorforceRequestedDate,
45+
value=DateValue(operator=DateOperator.GreaterThanOrEqual,
46+
value="2024-01-01"))
47+
year_from_now = (datetime.now() + timedelta(days=365)).strftime("%Y-%m-%d")
48+
workforce_requested_filter_after = WorkforceRequestedDateFilter(
49+
operation=OperationType.WorforceRequestedDate,
50+
value=DateValue(operator=DateOperator.LessThanOrEqual,
51+
value=year_from_now))
52+
53+
labeling_service_dashboard = [
54+
ld for ld in project.client.get_labeling_service_dashboards(search_query=[workforce_requested_filter_after, workforce_requested_filter_before])
55+
][0]
56+
assert labeling_service_dashboard is not None
57+
58+
workforce_date_range_filter = WorkforceRequestedDateRangeFilter(
59+
operation=OperationType.WorforceRequestedDate,
60+
value=DateRangeValue(operator=DateRangeOperator.Between,
61+
value=DateRange(min="2024-01-01",
62+
max=year_from_now)))
63+
64+
labeling_service_dashboard = [
65+
ld for ld in project.client.get_labeling_service_dashboards(search_query=[workforce_date_range_filter])
66+
][0]
67+
assert labeling_service_dashboard is not None
68+
69+
# with non existing data
70+
workspace_id = "clzzu4rme000008l42vnl4kre"
71+
workspace_filter = WorkspaceFilter(
72+
operation=OperationType.Workspace,
73+
operator=IdOperator.Is,
74+
values=[workspace_id])
75+
labeling_service_dashboard = [
76+
ld for ld in project.client.get_labeling_service_dashboards(search_query=[workspace_filter])
77+
]
78+
assert len(labeling_service_dashboard) == 0
79+
assert labeling_service_dashboard == []

libs/labelbox/tests/unit/test_unit_search_filters.py

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,4 @@
1-
import pytest
2-
3-
from labelbox.schema.search_filters import DateOperator, DateRange, DateRangeOperator, DateRangeValue, DateValue, IdOperator, OperationType, OrganizationFilter, ProjectStageFilter, TagFilter, WorkforceRequestedDateFilter, WorkforceRequestedDateRangeFilter, WorkforceStageUpdatedFilter, WorkforceStageUpdatedRangeFilter, WorkspaceFilter, _build_search_filter
4-
from test.test_pdb import pdb
5-
6-
7-
def test_duplicate_filters():
8-
filters = [
9-
OrganizationFilter(operation=OperationType.Organization,
10-
operator=IdOperator.Is,
11-
values=["clphb4vd7000cd2wv1ktu5cwa"]),
12-
WorkspaceFilter(operation=OperationType.Workspace,
13-
operator=IdOperator.Is,
14-
values=["clphb4vd7000cd2wv1ktu5cwa"]),
15-
TagFilter(operation=OperationType.Tag,
16-
operator=IdOperator.Is,
17-
values=["tag"]),
18-
ProjectStageFilter(operation=OperationType.Stage,
19-
operator=IdOperator.Is,
20-
values=["done"]),
21-
WorkforceRequestedDateFilter(
22-
operation=OperationType.WorforceRequestedDate,
23-
operator=DateOperator.Equals,
24-
value="2024-01-01"),
25-
WorkforceStageUpdatedFilter(
26-
operation=OperationType.WorkforceStageUpdatedDate,
27-
operator=DateOperator.Equals,
28-
value="2024-01-01"),
29-
WorkforceRequestedDateRangeFilter(
30-
operation=OperationType.WorforceRequestedDate,
31-
value=DateRangeValue(operator=DateRangeOperator.Between,
32-
value=DateRange(min="2024-01-01",
33-
max="2025-01-01"))),
34-
WorkforceStageUpdatedRangeFilter(
35-
operation=OperationType.WorkforceStageUpdatedDate,
36-
value=DateRangeValue(operator=DateRangeOperator.Between,
37-
value=DateRange(min="2024-01-01",
38-
max="2025-01-01")))
39-
]
40-
41-
with pytest.raises(ValueError):
42-
_build_search_filter(filters)
1+
from labelbox.schema.search_filters import DateOperator, DateRange, DateRangeOperator, DateRangeValue, DateValue, IdOperator, OperationType, OrganizationFilter, ProjectStageFilter, TagFilter, WorkforceRequestedDateFilter, WorkforceRequestedDateRangeFilter, WorkforceStageUpdatedFilter, WorkforceStageUpdatedRangeFilter, WorkspaceFilter, build_search_filter
432

443

454
def test_id_filters():
@@ -58,7 +17,7 @@ def test_id_filters():
5817
values=["requested"]),
5918
]
6019

61-
assert _build_search_filter(filters) == [{
20+
assert build_search_filter(filters) == [{
6221
"operator": "is",
6322
"values": ["clphb4vd7000cd2wv1ktu5cwa"],
6423
"type": "organization"
@@ -88,7 +47,7 @@ def test_date_filters():
8847
value=DateValue(operator=DateOperator.LessThanOrEqual,
8948
value="2025-01-01")),
9049
]
91-
assert _build_search_filter(filters) == [{
50+
assert build_search_filter(filters) == [{
9251
"type": "workforce_requested_at",
9352
"value": {
9453
"operator": "GREATER_THAN_OR_EQUAL",
@@ -116,7 +75,7 @@ def test_date_range_filters():
11675
value=DateRange(min="2024-01-01",
11776
max="2025-01-01")))
11877
]
119-
assert _build_search_filter(filters) == [{
78+
assert build_search_filter(filters) == [{
12079
"value": {
12180
"operator": "BETWEEN",
12281
"value": {

0 commit comments

Comments
 (0)