From f3292fc3288205eedc5cf262d984e36c17b507c9 Mon Sep 17 00:00:00 2001 From: jeremyzyngeraneo Date: Wed, 18 Oct 2023 11:36:52 +0200 Subject: [PATCH] feat: Add Result List with a Status Filter to Python --- packages/python/src/armonik/client/results.py | 35 +++++++++++++++++-- .../python/src/armonik/common/__init__.py | 2 +- .../python/src/armonik/common/enumwrapper.py | 13 ++++++- packages/python/src/armonik/common/objects.py | 35 ++++++++++++++++--- 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/packages/python/src/armonik/client/results.py b/packages/python/src/armonik/client/results.py index 642fc346f..942add9c1 100644 --- a/packages/python/src/armonik/client/results.py +++ b/packages/python/src/armonik/client/results.py @@ -1,11 +1,19 @@ from __future__ import annotations from grpc import Channel -from typing import List, Dict, cast +from typing import List, Dict, cast, Tuple from ..protogen.client.results_service_pb2_grpc import ResultsStub -from ..protogen.common.results_common_pb2 import CreateResultsMetaDataRequest, CreateResultsMetaDataResponse +from ..protogen.common.results_common_pb2 import CreateResultsMetaDataRequest, CreateResultsMetaDataResponse, ListResultsRequest, ListResultsResponse +from ..protogen.common.results_filters_pb2 import Filters as rawFilters, FiltersAnd as rawFilterAnd, FilterField as rawFilterField, FilterStatus as rawFilterStatus +from ..protogen.common.results_fields_pb2 import ResultField +from ..common.filter import StringFilter, StatusFilter, DateFilter, NumberFilter, Filter +from ..protogen.common.sort_direction_pb2 import SortDirection +from ..common import Direction , Result +from ..protogen.common.results_fields_pb2 import ResultField, ResultRawField, ResultRawEnumField, RESULT_RAW_ENUM_FIELD_STATUS +class ResultFieldFilter: + STATUS = StatusFilter(ResultField(result_raw_field=ResultRawField(field=RESULT_RAW_ENUM_FIELD_STATUS)), rawFilters, rawFilterAnd, rawFilterField, rawFilterStatus) class ArmoniKResult: def __init__(self, grpc_channel: Channel): @@ -18,3 +26,26 @@ def __init__(self, grpc_channel: Channel): def get_results_ids(self, session_id: str, names: List[str]) -> Dict[str, str]: return {r.name : r.result_id for r in cast(CreateResultsMetaDataResponse, self._client.CreateResultsMetaData(CreateResultsMetaDataRequest(results=[CreateResultsMetaDataRequest.ResultCreate(name = n) for n in names], session_id=session_id))).results} + + def list_results(self, result_filter: Filter, page: int = 0, page_size: int = 1000, sort_field: Filter = ResultFieldFilter.STATUS,sort_direction: SortDirection = Direction.ASC ) -> Tuple[int, List[Result]]: + """List results based on a filter. + + Args: + result_filter (Filter): Filter to apply when listing results + page: page number to request, useful for pagination, defaults to 0 + page_size: size of a page, defaults to 1000 + sort_field: field to sort the resulting list by, defaults to the status + sort_direction: direction of the sort, defaults to ascending + Returns: + A tuple containing : + - The total number of results for the given filter + - The obtained list of results + """ + request: ListResultsRequest = ListResultsRequest( + page=page, + page_size=page_size, + filters=cast(rawFilters, result_filter.to_disjunction().to_message()), + sort=ListResultsRequest.Sort(field=cast(ResultField, sort_field.field), direction=sort_direction), + ) + list_response: ListResultsResponse = self._client.ListResults(request) + return list_response.total, [Result.from_message(r) for r in list_response.results] diff --git a/packages/python/src/armonik/common/__init__.py b/packages/python/src/armonik/common/__init__.py index 7b6ba7ad6..001721868 100644 --- a/packages/python/src/armonik/common/__init__.py +++ b/packages/python/src/armonik/common/__init__.py @@ -1,4 +1,4 @@ from .helpers import datetime_to_timestamp, timestamp_to_datetime, duration_to_timedelta, timedelta_to_duration, get_task_filter -from .objects import Task, TaskDefinition, TaskOptions, Output, ResultAvailability, Session +from .objects import Task, TaskDefinition, TaskOptions, Output, ResultAvailability, Session, Result from .enumwrapper import HealthCheckStatus, TaskStatus, Direction from .filter import StringFilter, StatusFilter diff --git a/packages/python/src/armonik/common/enumwrapper.py b/packages/python/src/armonik/common/enumwrapper.py index 78e5fed8a..9c19a9a82 100644 --- a/packages/python/src/armonik/common/enumwrapper.py +++ b/packages/python/src/armonik/common/enumwrapper.py @@ -2,6 +2,7 @@ from ..protogen.common.task_status_pb2 import TaskStatus as RawStatus, _TASKSTATUS, TASK_STATUS_CANCELLED, TASK_STATUS_CANCELLING, TASK_STATUS_COMPLETED, TASK_STATUS_CREATING, TASK_STATUS_DISPATCHED, TASK_STATUS_ERROR, TASK_STATUS_PROCESSED, TASK_STATUS_PROCESSING, TASK_STATUS_SUBMITTED, TASK_STATUS_TIMEOUT, TASK_STATUS_UNSPECIFIED, TASK_STATUS_RETRIED from ..protogen.common.session_status_pb2 import SessionStatus as RawSessionStatus, _SESSIONSTATUS, SESSION_STATUS_UNSPECIFIED, SESSION_STATUS_CANCELLED, SESSION_STATUS_RUNNING +from ..protogen.common.result_status_pb2 import ResultStatus as RawResultStatus, _RESULTSTATUS, RESULT_STATUS_UNSPECIFIED, RESULT_STATUS_CREATED, RESULT_STATUS_COMPLETED, RESULT_STATUS_ABORTED, RESULT_STATUS_NOTFOUND from ..protogen.common.worker_common_pb2 import HealthCheckReply from ..protogen.common.sort_direction_pb2 import SORT_DIRECTION_ASC, SORT_DIRECTION_DESC @@ -46,4 +47,14 @@ def name_from_value(status: RawSessionStatus) -> str: UNSPECIFIED = SESSION_STATUS_UNSPECIFIED RUNNING = SESSION_STATUS_RUNNING CANCELLED = SESSION_STATUS_CANCELLED - \ No newline at end of file + +class ResultStatus: + @staticmethod + def name_from_value(status: RawResultStatus) -> str: + return _RESULTSTATUS.values_by_number[status].name + + UNSPECIFIED = RESULT_STATUS_UNSPECIFIED + CREATED = RESULT_STATUS_CREATED + COMPLETED = RESULT_STATUS_COMPLETED + ABORTED = RESULT_STATUS_ABORTED + NOTFOUND = RESULT_STATUS_NOTFOUND diff --git a/packages/python/src/armonik/common/objects.py b/packages/python/src/armonik/common/objects.py index 84a26c6b6..8debb5cbd 100644 --- a/packages/python/src/armonik/common/objects.py +++ b/packages/python/src/armonik/common/objects.py @@ -7,10 +7,11 @@ from .helpers import duration_to_timedelta, timedelta_to_duration, timestamp_to_datetime from ..protogen.common.objects_pb2 import Empty, Output as WorkerOutput, TaskOptions as RawTaskOptions from ..protogen.common.task_status_pb2 import TaskStatus as RawTaskStatus -from .enumwrapper import TaskStatus -from ..protogen.common.session_status_pb2 import * +from .enumwrapper import TaskStatus, SessionStatus, ResultStatus +from ..protogen.common.session_status_pb2 import SessionStatus as RawSessionStatus from ..protogen.common.sessions_common_pb2 import SessionRaw - +from ..protogen.common.result_status_pb2 import ResultStatus as RawResultStatus +from ..protogen.common.results_common_pb2 import ResultRaw @dataclass() class TaskOptions: @@ -164,7 +165,7 @@ def is_available(self) -> bool: @dataclass class Session: session_id: Optional[str] = None - status: SessionStatus = SESSION_STATUS_UNSPECIFIED + status: RawSessionStatus = SessionStatus.UNSPECIFIED partition_ids: List[str] = field(default_factory=list) options: Optional[TaskOptions] = None created_at: Optional[datetime] = None @@ -182,3 +183,29 @@ def from_message(cls, session_raw: SessionRaw) -> "Session": cancelled_at=timestamp_to_datetime(session_raw.cancelled_at), duration=duration_to_timedelta(session_raw.duration) ) + +from dataclasses import dataclass, field +from typing import List, Optional +from datetime import datetime + +@dataclass +class Result: + session_id: Optional[str] = None + name: Optional[str] = None + owner_task_id: Optional[str] = None + status: RawResultStatus = ResultStatus.UNSPECIFIED + created_at: Optional[datetime] = None + completed_at: Optional[datetime] = None + result_id: Optional[str] = None + + @classmethod + def from_message(cls, result_raw: ResultRaw) -> "Result": + return cls( + session_id=result_raw.session_id, + name=result_raw.name, + owner_task_id=result_raw.owner_task_id, + status=result_raw.status, + created_at=timestamp_to_datetime(result_raw.created_at), + completed_at=timestamp_to_datetime(result_raw.completed_at), + result_id=result_raw.result_id + )