From 9eecaeffcbbf50a996e640a681f0b9e95129a39d Mon Sep 17 00:00:00 2001 From: Tillman Date: Fri, 22 Dec 2023 19:11:05 +0100 Subject: [PATCH 01/34] Start refactoring on index_invocations operations --- lib/galaxy/webapps/galaxy/api/workflows.py | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index a67481078558..bed348a4a6a6 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -96,6 +96,8 @@ Router, search_query_param, ) +from galaxy.webapps.galaxy.api.common import SerializationViewQueryParam +from galaxy.webapps.galaxy.api.jobs import HistoryIdQueryParam from galaxy.webapps.galaxy.services.base import ( ConsumesModelStores, ServesExportStores, @@ -1265,11 +1267,110 @@ def get_workflow_menu( ), ] +JobIdQueryParam = Annotated[ + Optional[DecodedDatabaseIdField], + Query( + title="Job ID", + description="The encoded database identifier of the Job.", + ), +] + +UserIdQueryParam = Annotated[ + Optional[DecodedDatabaseIdField], + Query( + title="User ID", + description="The encoded database identifier of the User.", + ), +] + @router.cbv class FastAPIInvocations: invocations_service: InvocationsService = depends(InvocationsService) + @router.get( + "/api/invocations", + summary="Get the list of a user's workflow invocations.", + name="index_invocations", + ) + def index_invocations( + self, + job_id: Annotated[DecodedDatabaseIdField, JobIdQueryParam], + trans: ProvidesUserContext = DependsOnTrans, + history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, + user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, + workflow_id: Optional[DecodedDatabaseIdField] = None, + view: Annotated[Optional[str], SerializationViewQueryParam] = None, + instance: Annotated[Optional[bool], InstanceQueryParam] = False, + step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, + ): + """If workflow_id is supplied (either via URL or query parameter) it should be an + encoded StoredWorkflow id and returned invocations will be restricted to that + workflow. history_id (an encoded History id) can be used to further restrict the + query. If neither a workflow_id or history_id is supplied, all the current user's + workflow invocations will be indexed (as determined by the invocation being + executed on one of the user's histories)""" + invocation_payload = InvocationIndexPayload( + job_id=job_id, + history_id=history_id, + user_id=user_id, + workflow_id=workflow_id, + instance=instance, + ) + serialization_params = InvocationSerializationParams( + view=view, + step_details=step_details, + ) + invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) + trans.response.headers["total_matches"] = total_matches + return invocations + + @router.get( + "/api/workflows/{workflow_id}/invocations", + summary="Get the list of a user's workflow invocations.", + name="index_invocations", + ) + def index_workflow_invocations( + self, + job_id: Annotated[DecodedDatabaseIdField, JobIdQueryParam], + history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, + user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, + workflow_id: Annotated[Optional[DecodedDatabaseIdField], StoredWorkflowIDPathParam] = None, + view: Annotated[Optional[str], SerializationViewQueryParam] = None, + instance: bool = False, + step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, + trans: ProvidesUserContext = DependsOnTrans, + ): + """An alias for GET '/api/invocations'""" + self.index_invocations( + job_id=job_id, + history_id=history_id, + user_id=user_id, + workflow_id=workflow_id, + view=view, + instance=instance, + step_details=step_details, + trans=trans, + ) + + # :param workflow_id: an encoded stored workflow id to restrict query to + # :type workflow_id: str + + # :param instance: true if fetch by Workflow ID instead of StoredWorkflow id, false + # by default. + # :type instance: boolean + + # :param history_id: an encoded history id to restrict query to + # :type history_id: str + + # :param job_id: an encoded job id to restrict query to + # :type job_id: str + + # :param user_id: an encoded user id to restrict query to, must be own id if not admin user + # :type user_id: str + + # :raises: exceptions.MessageException, exceptions.ObjectNotFound + @router.post( "/api/invocations/{invocation_id}/prepare_store_download", summary="Prepare a workflow invocation export-style download.", From 416d62998ccb9f87c1df68887084aa0a4867e664 Mon Sep 17 00:00:00 2001 From: Tillman Date: Fri, 29 Dec 2023 16:37:49 +0100 Subject: [PATCH 02/34] Modify param definition to make it reusable --- lib/galaxy/webapps/galaxy/api/common.py | 14 ++++++++------ lib/galaxy/webapps/galaxy/api/configuration.py | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/common.py b/lib/galaxy/webapps/galaxy/api/common.py index 1e2cb1641956..952d1bbf5975 100644 --- a/lib/galaxy/webapps/galaxy/api/common.py +++ b/lib/galaxy/webapps/galaxy/api/common.py @@ -87,11 +87,13 @@ Path(..., title="Quota ID", description="The ID of the Quota."), ] -SerializationViewQueryParam: Optional[str] = Query( - None, - title="View", - description="View to be passed to the serializer", -) +SerializationViewQueryParam = Annotated[ + Optional[str], + Query( + title="View", + description="View to be passed to the serializer", + ), +] SerializationKeysQueryParam: Optional[str] = Query( None, @@ -151,7 +153,7 @@ def parse_serialization_params( def query_serialization_params( - view: Optional[str] = SerializationViewQueryParam, + view: Annotated[Optional[str], SerializationViewQueryParam] = None, keys: Optional[str] = SerializationKeysQueryParam, ) -> SerializationParams: return parse_serialization_params(view=view, keys=keys) diff --git a/lib/galaxy/webapps/galaxy/api/configuration.py b/lib/galaxy/webapps/galaxy/api/configuration.py index daa50afaf822..7e6006b97bed 100644 --- a/lib/galaxy/webapps/galaxy/api/configuration.py +++ b/lib/galaxy/webapps/galaxy/api/configuration.py @@ -11,6 +11,7 @@ ) from fastapi import Path +from typing_extensions import Annotated from galaxy.managers.configuration import ConfigurationManager from galaxy.managers.context import ProvidesUserContext @@ -60,7 +61,7 @@ def whoami(self, trans: ProvidesUserContext = DependsOnTrans) -> Optional[UserMo def index( self, trans: ProvidesUserContext = DependsOnTrans, - view: Optional[str] = SerializationViewQueryParam, + view: Annotated[Optional[str], SerializationViewQueryParam] = None, keys: Optional[str] = SerializationKeysQueryParam, ) -> Dict[str, Any]: """ From d7a81bb24e546f4139184d8f02bea0cbe41b6558 Mon Sep 17 00:00:00 2001 From: Tillman Date: Fri, 29 Dec 2023 17:28:06 +0100 Subject: [PATCH 03/34] Remove mapping to legacy route --- lib/galaxy/webapps/galaxy/buildapp.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index a17a122d47da..4c1cf66da571 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -673,14 +673,6 @@ def populate_api_routes(webapp, app): # conditions=dict(method=["POST"]), # ) - webapp.mapper.connect( - "list_invocations", - "/api/invocations", - controller="workflows", - action="index_invocations", - conditions=dict(method=["GET"]), - ) - webapp.mapper.connect( "create_invovactions_from_store", "/api/invocations/from_store", @@ -697,13 +689,6 @@ def populate_api_routes(webapp, app): } for noun, suffix in invoke_names.items(): name = f"{noun}{suffix}" - webapp.mapper.connect( - f"list_workflow_{name}", - "/api/workflows/{workflow_id}/%s" % noun, - controller="workflows", - action="index_invocations", - conditions=dict(method=["GET"]), - ) webapp.mapper.connect( f"workflow_{name}", "/api/workflows/{workflow_id}/%s" % noun, From ac2c3b2307ea478f46e86cb8d4e3d1c8c4018470 Mon Sep 17 00:00:00 2001 From: Tillman Date: Fri, 29 Dec 2023 17:29:18 +0100 Subject: [PATCH 04/34] Refactor index_invocations operations --- lib/galaxy/webapps/galaxy/api/workflows.py | 136 ++++++--------------- 1 file changed, 40 insertions(+), 96 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index bed348a4a6a6..263857a445de 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -97,7 +97,6 @@ search_query_param, ) from galaxy.webapps.galaxy.api.common import SerializationViewQueryParam -from galaxy.webapps.galaxy.api.jobs import HistoryIdQueryParam from galaxy.webapps.galaxy.services.base import ( ConsumesModelStores, ServesExportStores, @@ -793,49 +792,6 @@ def invoke(self, trans: GalaxyWebTransaction, workflow_id, payload, **kwd): else: return encoded_invocations[0] - @expose_api - def index_invocations(self, trans: GalaxyWebTransaction, **kwd): - """ - GET /api/workflows/{workflow_id}/invocations - GET /api/invocations - - Get the list of a user's workflow invocations. If workflow_id is supplied - (either via URL or query parameter) it should be an encoded StoredWorkflow id - and returned invocations will be restricted to that workflow. history_id (an encoded - History id) can be used to further restrict the query. If neither a workflow_id or - history_id is supplied, all the current user's workflow invocations will be indexed - (as determined by the invocation being executed on one of the user's histories). - - :param workflow_id: an encoded stored workflow id to restrict query to - :type workflow_id: str - - :param instance: true if fetch by Workflow ID instead of StoredWorkflow id, false - by default. - :type instance: boolean - - :param history_id: an encoded history id to restrict query to - :type history_id: str - - :param job_id: an encoded job id to restrict query to - :type job_id: str - - :param user_id: an encoded user id to restrict query to, must be own id if not admin user - :type user_id: str - - :param view: level of detail to return per invocation 'element' or 'collection'. - :type view: str - - :param step_details: If 'view' is 'element', also include details on individual steps. - :type step_details: bool - - :raises: exceptions.MessageException, exceptions.ObjectNotFound - """ - invocation_payload = InvocationIndexPayload(**kwd) - serialization_params = InvocationSerializationParams(**kwd) - invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) - trans.response.headers["total_matches"] = total_matches - return [i.model_dump(mode="json") for i in invocations] - @expose_api_anonymous def create_invocations_from_store(self, trans, payload, **kwd): """ @@ -999,9 +955,12 @@ def __get_stored_workflow(self, trans, workflow_id, **kwd): title="Number of workflows to skip in sorted query (to enable pagination).", ) -InstanceQueryParam: Optional[bool] = Query( - default=False, title="True when fetching by Workflow ID, False when fetching by StoredWorkflow ID." -) +InstanceQueryParam = Annotated[ + Optional[bool], + Query( + title="True when fetching by Workflow ID, False when fetching by StoredWorkflow ID.", + ), +] query_tags = [ IndexQueryTag("name", "The stored workflow's name.", "n"), @@ -1195,9 +1154,9 @@ def undelete_workflow( ) def show_versions( self, - workflow_id: StoredWorkflowIDPathParam, trans: ProvidesUserContext = DependsOnTrans, - instance: Optional[bool] = InstanceQueryParam, + workflow_id: DecodedDatabaseIdField = StoredWorkflowIDPathParam, + instance: Annotated[Optional[bool], InstanceQueryParam] = False, ): return self.service.get_versions(trans, workflow_id, instance) @@ -1249,24 +1208,15 @@ def get_workflow_menu( ), ] - -HistoryIdQueryParam: Annotated[ +# TODO rename? - this is already defined in jobs.py +HistoryIdQueryParam = Annotated[ Optional[DecodedDatabaseIdField], Query( - default=None, + title="History ID", description="Optional identifier of a History. Use it to restrict the search within a particular History.", ), ] - -JobIdQueryParam = Annotated[ - DecodedDatabaseIdField, - Query( - title="Job ID", - description="The ID of the job", - ), -] - JobIdQueryParam = Annotated[ Optional[DecodedDatabaseIdField], Query( @@ -1283,6 +1233,14 @@ def get_workflow_menu( ), ] +WorkflowIdQueryParam = Annotated[ + Optional[DecodedDatabaseIdField], + Query( + title="Workflow ID", + description="Return only invocations for this Workflow ID", + ), +] + @router.cbv class FastAPIInvocations: @@ -1295,34 +1253,37 @@ class FastAPIInvocations: ) def index_invocations( self, - job_id: Annotated[DecodedDatabaseIdField, JobIdQueryParam], - trans: ProvidesUserContext = DependsOnTrans, + workflow_id: Annotated[Optional[DecodedDatabaseIdField], WorkflowIdQueryParam] = None, history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, + job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, - workflow_id: Optional[DecodedDatabaseIdField] = None, - view: Annotated[Optional[str], SerializationViewQueryParam] = None, instance: Annotated[Optional[bool], InstanceQueryParam] = False, + view: Annotated[Optional[str], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, + trans: ProvidesUserContext = DependsOnTrans, ): """If workflow_id is supplied (either via URL or query parameter) it should be an encoded StoredWorkflow id and returned invocations will be restricted to that workflow. history_id (an encoded History id) can be used to further restrict the query. If neither a workflow_id or history_id is supplied, all the current user's workflow invocations will be indexed (as determined by the invocation being - executed on one of the user's histories)""" + executed on one of the user's histories) + :raises: exceptions.MessageException, exceptions.ObjectNotFound + """ invocation_payload = InvocationIndexPayload( - job_id=job_id, - history_id=history_id, - user_id=user_id, - workflow_id=workflow_id, instance=instance, ) + invocation_payload.workflow_id = workflow_id + invocation_payload.history_id = history_id + invocation_payload.job_id = job_id + invocation_payload.user_id = user_id serialization_params = InvocationSerializationParams( view=view, step_details=step_details, ) invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) - trans.response.headers["total_matches"] = total_matches + # TODO - how to access this via 'new' trans + # trans.response.headers["total_matches"] = total_matches return invocations @router.get( @@ -1332,44 +1293,27 @@ def index_invocations( ) def index_workflow_invocations( self, - job_id: Annotated[DecodedDatabaseIdField, JobIdQueryParam], + workflow_id: Annotated[DecodedDatabaseIdField, StoredWorkflowIDPathParam], history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, + job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, - workflow_id: Annotated[Optional[DecodedDatabaseIdField], StoredWorkflowIDPathParam] = None, + instance: Annotated[Optional[bool], InstanceQueryParam] = False, view: Annotated[Optional[str], SerializationViewQueryParam] = None, - instance: bool = False, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, ): """An alias for GET '/api/invocations'""" - self.index_invocations( - job_id=job_id, + invocations = self.index_invocations( history_id=history_id, + job_id=job_id, user_id=user_id, - workflow_id=workflow_id, - view=view, instance=instance, + view=view, step_details=step_details, + workflow_id=workflow_id, trans=trans, ) - - # :param workflow_id: an encoded stored workflow id to restrict query to - # :type workflow_id: str - - # :param instance: true if fetch by Workflow ID instead of StoredWorkflow id, false - # by default. - # :type instance: boolean - - # :param history_id: an encoded history id to restrict query to - # :type history_id: str - - # :param job_id: an encoded job id to restrict query to - # :type job_id: str - - # :param user_id: an encoded user id to restrict query to, must be own id if not admin user - # :type user_id: str - - # :raises: exceptions.MessageException, exceptions.ObjectNotFound + return invocations @router.post( "/api/invocations/{invocation_id}/prepare_store_download", From 8a1604e357a4d6156852466212feaedcd3e823ec Mon Sep 17 00:00:00 2001 From: Tillman Date: Sat, 30 Dec 2023 15:22:48 +0100 Subject: [PATCH 05/34] Move model CreateInvocationFromStore to invocation schema file --- lib/galaxy/schema/invocation.py | 11 ++++++++++- lib/galaxy/webapps/galaxy/api/workflows.py | 8 +------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 097f56ee82e1..37b6ed298364 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -41,6 +41,7 @@ JOB_MODEL_CLASS, JobState, Model, + StoreContentSource, UpdateTimeField, WithModelClass, ) @@ -590,4 +591,12 @@ class InvocationStepJobsResponseJobModel(InvocationJobsSummaryBaseModel): class InvocationStepJobsResponseCollectionJobsModel(InvocationJobsSummaryBaseModel): - model: IMPLICIT_COLLECTION_JOBS_MODEL_CLASS + model: IMPLICIT_COLLECTION_JOBS_MODEL_CLASS = ModelClassField(IMPLICIT_COLLECTION_JOBS_MODEL_CLASS) + + +class CreateInvocationFromStore(StoreContentSource): + # TODO - add proper description + history_id: Optional[str] = Field(default=None, title="History ID", description="History ID.") + + class Config: + extra = Extra.allow diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 263857a445de..c080ff389618 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -23,7 +23,6 @@ ) from gxformat2._yaml import ordered_dump from markupsafe import escape -from pydantic import ConfigDict from starlette.responses import StreamingResponse from typing_extensions import Annotated @@ -48,6 +47,7 @@ from galaxy.model.store import BcoExportOptions from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.invocation import ( + CreateInvocationFromStore, InvocationJobsResponse, InvocationMessageResponseModel, InvocationReport, @@ -65,7 +65,6 @@ ShareWithPayload, ShareWithStatus, SharingStatus, - StoreContentSource, WorkflowSortByEnum, ) from galaxy.structured_app import StructuredApp @@ -122,11 +121,6 @@ router = Router(tags=["workflows"]) -class CreateInvocationFromStore(StoreContentSource): - history_id: Optional[str] - model_config = ConfigDict(extra="allow") - - class WorkflowsAPIController( BaseGalaxyAPIController, UsesStoredWorkflowMixin, From 687b65ccef56d677e58849104f4193eb52c0d50b Mon Sep 17 00:00:00 2001 From: Tillman Date: Sat, 30 Dec 2023 15:25:24 +0100 Subject: [PATCH 06/34] Refactor internal method create_from_store into invocations service --- lib/galaxy/webapps/galaxy/api/workflows.py | 17 +------------- .../webapps/galaxy/services/invocations.py | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index c080ff389618..618368715dd2 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -800,22 +800,7 @@ def create_invocations_from_store(self, trans, payload, **kwd): create_payload = CreateInvocationFromStore(**payload) serialization_params = InvocationSerializationParams(**payload) # refactor into a service... - return [i.model_dump(mode="json") for i in self._create_from_store(trans, create_payload, serialization_params)] - - def _create_from_store( - self, trans, payload: CreateInvocationFromStore, serialization_params: InvocationSerializationParams - ): - history = self.history_manager.get_owned( - self.decode_id(payload.history_id), trans.user, current_history=trans.history - ) - object_tracker = self.create_objects_from_store( - trans, - payload, - history=history, - ) - return self.invocations_service.serialize_workflow_invocations( - object_tracker.invocations_by_key.values(), serialization_params - ) + return self.invocations_service.create_from_store(trans, create_payload, serialization_params) def _workflow_from_dict(self, trans, data, workflow_create_options, source=None): """Creates a workflow from a dict. diff --git a/lib/galaxy/webapps/galaxy/services/invocations.py b/lib/galaxy/webapps/galaxy/services/invocations.py index 220d1567c01f..a4c18d8f3839 100644 --- a/lib/galaxy/webapps/galaxy/services/invocations.py +++ b/lib/galaxy/webapps/galaxy/services/invocations.py @@ -22,6 +22,7 @@ AdminRequiredException, ObjectNotFound, ) +from galaxy.managers.context import ProvidesHistoryContext from galaxy.managers.histories import HistoryManager from galaxy.managers.jobs import ( fetch_job_states, @@ -38,6 +39,8 @@ ) from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.invocation import ( + CreateInvocationFromStore, + InvocationMessageResponseModel, InvocationStep, WorkflowInvocationResponse, ) @@ -57,6 +60,7 @@ from galaxy.short_term_storage import ShortTermStorageAllocator from galaxy.webapps.galaxy.services.base import ( async_task_summary, + ConsumesModelStores, ensure_celery_tasks_enabled, model_store_storage_target, ServiceBase, @@ -110,7 +114,7 @@ class WriteInvocationStoreToPayload(WriteStoreToPayload, BcoGenerationParameters pass -class InvocationsService(ServiceBase): +class InvocationsService(ServiceBase, ConsumesModelStores): def __init__( self, security: IdEncodingHelper, @@ -287,3 +291,19 @@ def deprecated_generate_invocation_bco( export_store.export_workflow_invocation(workflow_invocation) export_target.seek(0) return export_target.read() + + def create_from_store( + self, + trans: ProvidesHistoryContext, + payload: CreateInvocationFromStore, + serialization_params: InvocationSerializationParams, + ): + history = self._histories_manager.get_owned( + self.decode_id(payload.history_id), trans.user, current_history=trans.history + ) + object_tracker = self.create_objects_from_store( + trans, + payload, + history=history, + ) + return self.serialize_workflow_invocations(object_tracker.invocations_by_key.values(), serialization_params) From 714011e85f46151f8bf3a6477d34b86405422274 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sat, 30 Dec 2023 19:17:34 +0100 Subject: [PATCH 07/34] Move model InvocationSerializationParams to invocations schema file --- lib/galaxy/schema/invocation.py | 32 ++++++++++++++ .../webapps/galaxy/services/invocations.py | 42 ++----------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 37b6ed298364..434c7c9b5c33 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -600,3 +600,35 @@ class CreateInvocationFromStore(StoreContentSource): class Config: extra = Extra.allow + + +class InvocationSerializationView(str, Enum): + element = "element" + collection = "collection" + + +class InvocationSerializationParams(Model): + """Contains common parameters for customizing model serialization.""" + + view: Optional[InvocationSerializationView] = Field( + default=None, + title="View", + description=( + "The name of the view used to serialize this item. " + "This will return a predefined set of attributes of the item." + ), + example="element", + ) + step_details: bool = Field( + default=False, + title="Include step details", + description="Include details for individual invocation steps and populate a steps attribute in the resulting dictionary", + ) + legacy_job_state: bool = Field( + default=False, + description="""Populate the invocation step state with the job state instead of the invocation step state. + This will also produce one step per job in mapping jobs to mimic the older behavior with respect to collections. + Partially scheduled steps may provide incomplete information and the listed steps outputs + are not the mapped over step outputs but the individual job outputs.""", + deprecated=True, + ) diff --git a/lib/galaxy/webapps/galaxy/services/invocations.py b/lib/galaxy/webapps/galaxy/services/invocations.py index a4c18d8f3839..22d945d992db 100644 --- a/lib/galaxy/webapps/galaxy/services/invocations.py +++ b/lib/galaxy/webapps/galaxy/services/invocations.py @@ -1,18 +1,13 @@ import logging -from enum import Enum from tempfile import NamedTemporaryFile from typing import ( Any, Dict, List, - Optional, Tuple, ) -from pydantic import ( - BaseModel, - Field, -) +from pydantic import Field from galaxy.celery.tasks import ( prepare_invocation_download, @@ -41,6 +36,8 @@ from galaxy.schema.invocation import ( CreateInvocationFromStore, InvocationMessageResponseModel, + InvocationSerializationParams, + InvocationSerializationView, InvocationStep, WorkflowInvocationResponse, ) @@ -69,39 +66,6 @@ log = logging.getLogger(__name__) -class InvocationSerializationView(str, Enum): - element = "element" - collection = "collection" - - -class InvocationSerializationParams(BaseModel): - """Contains common parameters for customizing model serialization.""" - - view: Optional[InvocationSerializationView] = Field( - default=None, - title="View", - description=( - "The name of the view used to serialize this item. " - "This will return a predefined set of attributes of the item." - ), - examples=["element"], - ) - step_details: bool = Field( - default=False, - title="Include step details", - description="Include details for individual invocation steps and populate a steps attribute in the resulting dictionary", - ) - legacy_job_state: bool = Field( - default=False, - description="""Populate the invocation step state with the job state instead of the invocation step state. - This will also produce one step per job in mapping jobs to mimic the older behavior with respect to collections. - Partially scheduled steps may provide incomplete information and the listed steps outputs - are not the mapped over step outputs but the individual job outputs.""", - # TODO: also deprecate on python side, https://github.com/pydantic/pydantic/issues/2255 - json_schema_extra={"deprecated": True}, - ) - - class InvocationIndexPayload(InvocationIndexQueryPayload): instance: bool = Field(default=False, description="Is provided workflow id for Workflow instead of StoredWorkflow?") From dd8269a9a108a10a172ad1d0c08147e93e2a4870 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sat, 30 Dec 2023 19:19:23 +0100 Subject: [PATCH 08/34] Refactor create_invocations_from_store operation to FastAPI --- lib/galaxy/schema/invocation.py | 4 ++ lib/galaxy/webapps/galaxy/api/workflows.py | 54 +++++++++++++++------- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 434c7c9b5c33..c6730d8b785d 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -632,3 +632,7 @@ class InvocationSerializationParams(Model): are not the mapped over step outputs but the individual job outputs.""", deprecated=True, ) + + +class CreateInvocationsFromStorePayload(CreateInvocationFromStore, InvocationSerializationParams): + pass diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 618368715dd2..6136bc75d14a 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -35,7 +35,10 @@ stream_url_to_str, validate_uri_access, ) -from galaxy.managers.context import ProvidesUserContext +from galaxy.managers.context import ( + ProvidesHistoryContext, + ProvidesUserContext, +) from galaxy.managers.workflows import ( MissingToolsException, RefactorRequest, @@ -48,9 +51,11 @@ from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.invocation import ( CreateInvocationFromStore, + CreateInvocationsFromStorePayload, InvocationJobsResponse, InvocationMessageResponseModel, InvocationReport, + InvocationSerializationParams, InvocationStep, InvocationStepJobsResponseCollectionJobsModel, InvocationStepJobsResponseJobModel, @@ -76,7 +81,6 @@ from galaxy.version import VERSION from galaxy.web import ( expose_api, - expose_api_anonymous, expose_api_anonymous_and_sessionless, expose_api_raw_anonymous_and_sessionless, format_return_as_json, @@ -102,7 +106,6 @@ ) from galaxy.webapps.galaxy.services.invocations import ( InvocationIndexPayload, - InvocationSerializationParams, InvocationsService, PrepareStoreDownloadPayload, WriteInvocationStoreToPayload, @@ -786,21 +789,21 @@ def invoke(self, trans: GalaxyWebTransaction, workflow_id, payload, **kwd): else: return encoded_invocations[0] - @expose_api_anonymous - def create_invocations_from_store(self, trans, payload, **kwd): - """ - POST /api/invocations/from_store + # @expose_api_anonymous + # def create_invocations_from_store(self, trans, payload, **kwd): + # """ + # POST /api/invocations/from_store - Create invocation(s) from a supplied model store. + # Create invocation(s) from a supplied model store. - Input can be an archive describing a Galaxy model store containing an - workflow invocation - for instance one created with with write_store - or prepare_store_download endpoint. - """ - create_payload = CreateInvocationFromStore(**payload) - serialization_params = InvocationSerializationParams(**payload) - # refactor into a service... - return self.invocations_service.create_from_store(trans, create_payload, serialization_params) + # Input can be an archive describing a Galaxy model store containing an + # workflow invocation - for instance one created with with write_store + # or prepare_store_download endpoint. + # """ + # create_payload = CreateInvocationFromStore(**payload) + # serialization_params = InvocationSerializationParams(**payload) + # # refactor into a service... + # return self.invocations_service.create_from_store(trans, create_payload, serialization_params) def _workflow_from_dict(self, trans, data, workflow_create_options, source=None): """Creates a workflow from a dict. @@ -1225,6 +1228,25 @@ def get_workflow_menu( class FastAPIInvocations: invocations_service: InvocationsService = depends(InvocationsService) + @router.post( + "/api/invocations/from_store", + name="create_invocations_from_store", + description="Create invocation(s) from a supplied model store.", + ) + def create_invocations_from_store( + self, + payload: Annotated[CreateInvocationsFromStorePayload, Body(...)], + trans: ProvidesHistoryContext = DependsOnTrans, + ): + """ + Input can be an archive describing a Galaxy model store containing an + workflow invocation - for instance one created with with write_store + or prepare_store_download endpoint. + """ + create_payload = CreateInvocationFromStore(**payload.dict()) + serialization_params = InvocationSerializationParams(**payload.dict()) + return self.invocations_service.create_from_store(trans, create_payload, serialization_params) + @router.get( "/api/invocations", summary="Get the list of a user's workflow invocations.", From cdc9a94620c2371b259f48df4c828d26c7051323 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sat, 30 Dec 2023 19:19:37 +0100 Subject: [PATCH 09/34] Remove mapping to legacy route --- lib/galaxy/webapps/galaxy/buildapp.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 4c1cf66da571..0e2d74676b4b 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -673,14 +673,6 @@ def populate_api_routes(webapp, app): # conditions=dict(method=["POST"]), # ) - webapp.mapper.connect( - "create_invovactions_from_store", - "/api/invocations/from_store", - controller="workflows", - action="create_invocations_from_store", - conditions=dict(method=["POST"]), - ) - # API refers to usages and invocations - these mean the same thing but the # usage routes should be considered deprecated. invoke_names = { From 975a0709f8c9c2801e039862f4e584a3cc5cc934 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sun, 31 Dec 2023 15:31:47 +0100 Subject: [PATCH 10/34] Refactor pydantic model to enable reuse --- lib/galaxy/schema/invocation.py | 41 ++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index c6730d8b785d..7390483d21b5 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -514,7 +514,11 @@ class InvocationOutputCollection(InvocationIOBase): ) +<<<<<<< HEAD class WorkflowInvocationCollectionView(Model, WithModelClass): +======= +class WorkflowInvocationBaseResponse(Model): +>>>>>>> Refactor pydantic model to enable reuse id: EncodedDatabaseIdField = InvocationIdField create_time: datetime = CreateTimeField update_time: datetime = UpdateTimeField @@ -532,10 +536,17 @@ class WorkflowInvocationCollectionView(Model, WithModelClass): ) state: InvocationState = Field(default=..., title="Invocation state", description="State of workflow invocation.") model_class: INVOCATION_MODEL_CLASS = ModelClassField(INVOCATION_MODEL_CLASS) + messages: List[InvocationMessageResponseUnion] = Field( + default=Required, + title="Messages", + description="A list of messages about why the invocation did not succeed.", + ) -class WorkflowInvocationElementView(WorkflowInvocationCollectionView): - steps: List[InvocationStep] = Field(default=..., title="Steps", description="Steps of the workflow invocation.") +class WorkflowInvocationResponse(WorkflowInvocationBaseResponse): + steps: List[InvocationStep] = Field( + default=Required, title="Steps", description="Steps of the workflow invocation." + ) inputs: Dict[str, InvocationInput] = Field( default=..., title="Inputs", description="Input datasets/dataset collections of the workflow invocation." ) @@ -553,10 +564,28 @@ class WorkflowInvocationElementView(WorkflowInvocationCollectionView): output_values: Dict[str, Any] = Field( default=..., title="Output values", description="Output values of the workflow invocation." ) - messages: List[InvocationMessageResponseUnion] = Field( - default=..., - title="Messages", - description="A list of messages about why the invocation did not succeed.", + + +class IndexWorkflowInvocationResponse(WorkflowInvocationBaseResponse): + steps: Optional[List[InvocationStep]] = Field( + default=None, title="Steps", description="Steps of the workflow invocation." + ) + inputs: Optional[Dict[str, InvocationInput]] = Field( + default=None, title="Inputs", description="Input datasets/dataset collections of the workflow invocation." + ) + input_step_parameters: Optional[Dict[str, InvocationInputParameter]] = Field( + default=None, title="Input step parameters", description="Input step parameters of the workflow invocation." + ) + outputs: Optional[Dict[str, InvocationOutput]] = Field( + default=None, title="Outputs", description="Output datasets of the workflow invocation." + ) + output_collections: Optional[Dict[str, InvocationOutputCollection]] = Field( + default=None, + title="Output collections", + description="Output dataset collections of the workflow invocation.", + ) + output_values: Optional[Dict[str, Any]] = Field( + default=None, title="Output values", description="Output values of the workflow invocation." ) From d1ef38339402f82af44b21ae7b12964c31ff79e1 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sun, 31 Dec 2023 15:32:16 +0100 Subject: [PATCH 11/34] Add pydantic model to return of operations --- lib/galaxy/webapps/galaxy/api/workflows.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 6136bc75d14a..acebd2d31067 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -52,10 +52,12 @@ from galaxy.schema.invocation import ( CreateInvocationFromStore, CreateInvocationsFromStorePayload, + IndexWorkflowInvocationResponse, InvocationJobsResponse, InvocationMessageResponseModel, InvocationReport, InvocationSerializationParams, + InvocationSerializationView, InvocationStep, InvocationStepJobsResponseCollectionJobsModel, InvocationStepJobsResponseJobModel, @@ -1237,7 +1239,7 @@ def create_invocations_from_store( self, payload: Annotated[CreateInvocationsFromStorePayload, Body(...)], trans: ProvidesHistoryContext = DependsOnTrans, - ): + ) -> List[IndexWorkflowInvocationResponse]: """ Input can be an archive describing a Galaxy model store containing an workflow invocation - for instance one created with with write_store @@ -1245,7 +1247,8 @@ def create_invocations_from_store( """ create_payload = CreateInvocationFromStore(**payload.dict()) serialization_params = InvocationSerializationParams(**payload.dict()) - return self.invocations_service.create_from_store(trans, create_payload, serialization_params) + invocations = self.invocations_service.create_from_store(trans, create_payload, serialization_params) + return [IndexWorkflowInvocationResponse(**invocation) for invocation in invocations] @router.get( "/api/invocations", @@ -1259,10 +1262,10 @@ def index_invocations( job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, instance: Annotated[Optional[bool], InstanceQueryParam] = False, - view: Annotated[Optional[str], SerializationViewQueryParam] = None, + view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, - ): + ) -> List[IndexWorkflowInvocationResponse]: """If workflow_id is supplied (either via URL or query parameter) it should be an encoded StoredWorkflow id and returned invocations will be restricted to that workflow. history_id (an encoded History id) can be used to further restrict the @@ -1285,7 +1288,7 @@ def index_invocations( invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) # TODO - how to access this via 'new' trans # trans.response.headers["total_matches"] = total_matches - return invocations + return [IndexWorkflowInvocationResponse(**invocation) for invocation in invocations] @router.get( "/api/workflows/{workflow_id}/invocations", @@ -1299,10 +1302,10 @@ def index_workflow_invocations( job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, instance: Annotated[Optional[bool], InstanceQueryParam] = False, - view: Annotated[Optional[str], SerializationViewQueryParam] = None, + view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, - ): + ) -> List[IndexWorkflowInvocationResponse]: """An alias for GET '/api/invocations'""" invocations = self.index_invocations( history_id=history_id, From fa9e021088f279d123c1700e4cb4add6ed1da2a5 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sun, 31 Dec 2023 15:43:31 +0100 Subject: [PATCH 12/34] Mark history_id as required in pydantic model for create_invocations_from_store --- lib/galaxy/schema/invocation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 7390483d21b5..2d243d3c5e3f 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -625,7 +625,7 @@ class InvocationStepJobsResponseCollectionJobsModel(InvocationJobsSummaryBaseMod class CreateInvocationFromStore(StoreContentSource): # TODO - add proper description - history_id: Optional[str] = Field(default=None, title="History ID", description="History ID.") + history_id: EncodedDatabaseIdField = Field(default=Required, title="History ID", description="") class Config: extra = Extra.allow From 101505ea597a2917d9d003edf952e63c1504833e Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 2 Jan 2024 15:12:59 +0100 Subject: [PATCH 13/34] Remove comment --- lib/galaxy/webapps/galaxy/api/workflows.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index acebd2d31067..16a32b274732 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -791,22 +791,6 @@ def invoke(self, trans: GalaxyWebTransaction, workflow_id, payload, **kwd): else: return encoded_invocations[0] - # @expose_api_anonymous - # def create_invocations_from_store(self, trans, payload, **kwd): - # """ - # POST /api/invocations/from_store - - # Create invocation(s) from a supplied model store. - - # Input can be an archive describing a Galaxy model store containing an - # workflow invocation - for instance one created with with write_store - # or prepare_store_download endpoint. - # """ - # create_payload = CreateInvocationFromStore(**payload) - # serialization_params = InvocationSerializationParams(**payload) - # # refactor into a service... - # return self.invocations_service.create_from_store(trans, create_payload, serialization_params) - def _workflow_from_dict(self, trans, data, workflow_create_options, source=None): """Creates a workflow from a dict. From 7a50e8bf6533299c9438b45b41b469f1055a2ed9 Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 2 Jan 2024 16:43:45 +0100 Subject: [PATCH 14/34] Set total_matches in response headers of index_inovcation operation --- lib/galaxy/webapps/galaxy/api/workflows.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 16a32b274732..06b6ce48e149 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -1241,6 +1241,7 @@ def create_invocations_from_store( ) def index_invocations( self, + response: Response, workflow_id: Annotated[Optional[DecodedDatabaseIdField], WorkflowIdQueryParam] = None, history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, @@ -1271,7 +1272,7 @@ def index_invocations( ) invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) # TODO - how to access this via 'new' trans - # trans.response.headers["total_matches"] = total_matches + response.headers["total_matches"] = str(total_matches) return [IndexWorkflowInvocationResponse(**invocation) for invocation in invocations] @router.get( @@ -1281,6 +1282,7 @@ def index_invocations( ) def index_workflow_invocations( self, + response: Response, workflow_id: Annotated[DecodedDatabaseIdField, StoredWorkflowIDPathParam], history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, @@ -1292,6 +1294,7 @@ def index_workflow_invocations( ) -> List[IndexWorkflowInvocationResponse]: """An alias for GET '/api/invocations'""" invocations = self.index_invocations( + response=response, history_id=history_id, job_id=job_id, user_id=user_id, From f0c34d1a48a62be472da618381de73400b36c27c Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 2 Jan 2024 16:52:35 +0100 Subject: [PATCH 15/34] Specify body of the payload of the create_invocations_from_store operations --- lib/galaxy/webapps/galaxy/api/workflows.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 06b6ce48e149..3eb46a1b4521 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -23,6 +23,7 @@ ) from gxformat2._yaml import ordered_dump from markupsafe import escape +from pydantic import Required from starlette.responses import StreamingResponse from typing_extensions import Annotated @@ -1209,6 +1210,15 @@ def get_workflow_menu( ), ] +CreateInvocationsFromStoreBody = Annotated[ + CreateInvocationsFromStorePayload, + Body( + default=Required, + title="Create invocations from store", + description="The values and serialization parameters for creating invocations from a supplied model store.", + ), +] + @router.cbv class FastAPIInvocations: @@ -1221,7 +1231,7 @@ class FastAPIInvocations: ) def create_invocations_from_store( self, - payload: Annotated[CreateInvocationsFromStorePayload, Body(...)], + payload: Annotated[CreateInvocationsFromStorePayload, CreateInvocationsFromStoreBody], trans: ProvidesHistoryContext = DependsOnTrans, ) -> List[IndexWorkflowInvocationResponse]: """ @@ -1271,7 +1281,6 @@ def index_invocations( step_details=step_details, ) invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) - # TODO - how to access this via 'new' trans response.headers["total_matches"] = str(total_matches) return [IndexWorkflowInvocationResponse(**invocation) for invocation in invocations] From bf9d1f560427cb966fe204d992c15e5b42bfa043 Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 2 Jan 2024 19:59:55 +0100 Subject: [PATCH 16/34] Remove unnecessary encoding of id's --- lib/galaxy/webapps/galaxy/services/invocations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/invocations.py b/lib/galaxy/webapps/galaxy/services/invocations.py index 22d945d992db..ecf50f1b5ced 100644 --- a/lib/galaxy/webapps/galaxy/services/invocations.py +++ b/lib/galaxy/webapps/galaxy/services/invocations.py @@ -157,12 +157,12 @@ def show_invocation_step_jobs_summary(self, trans, invocation_id) -> List[Dict[s for job_source_type, job_source_id, _ in invocation_job_source_iter(trans.sa_session, invocation_id): ids.append(job_source_id) types.append(job_source_type) - return fetch_job_states(trans.sa_session, ids, types) + return [s for s in fetch_job_states(trans.sa_session, ids, types)] def show_invocation_jobs_summary(self, trans, invocation_id) -> Dict[str, Any]: ids = [invocation_id] types = ["WorkflowInvocation"] - return fetch_job_states(trans.sa_session, ids, types)[0] + return [s for s in fetch_job_states(trans.sa_session, ids, types)][0] def prepare_store_download( self, trans, invocation_id: DecodedDatabaseIdField, payload: PrepareStoreDownloadPayload From 7195af85e9d48449a1834db07a2995b35d26d6fc Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 2 Jan 2024 20:01:02 +0100 Subject: [PATCH 17/34] Specify extra fields and adjust default values of fields in InvocationReport model --- lib/galaxy/schema/invocation.py | 52 ++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 2d243d3c5e3f..bed5bdd23312 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -428,12 +428,12 @@ class InvocationReport(Model, WithModelClass): description="Format of the invocation report.", ) markdown: Optional[str] = Field( - default="", + default=None, title="Markdown", description="Raw galaxy-flavored markdown contents of the report.", ) invocation_markdown: Optional[str] = Field( - default="", + default=None, title="Markdown", description="Raw galaxy-flavored markdown contents of the report.", ) @@ -455,7 +455,49 @@ class InvocationReport(Model, WithModelClass): ) generate_time: Optional[str] = schema.GenerateTimeField generate_version: Optional[str] = schema.GenerateVersionField - model_config = ConfigDict(extra="allow") + + errors: Optional[Dict[str, Any]] = Field( + default=None, + title="Errors", + description="Errors associated with the invocation.", + ) + + history_datasets: Optional[Dict[str, Any]] = Field( + default=None, + title="History datasets", + description="History datasets associated with the invocation.", + ) + workflows: Optional[Dict[str, Any]] = Field( + default=None, + title="Workflows", + description="Workflows associated with the invocation.", + ) + history_dataset_collections: Optional[Dict[str, Any]] = Field( + default=None, + title="History dataset collections", + description="History dataset collections associated with the invocation.", + ) + jobs: Optional[Dict[str, Any]] = Field( + default=None, + title="Jobs", + description="Jobs associated with the invocation.", + ) + histories: Optional[Dict[str, Any]] = Field( + default=None, + title="Histories", + description="Histories associated with the invocation.", + ) + invocations: Optional[Dict[str, Any]] = Field( + default=None, + title="Invocations", + description="Other invocations associated with the invocation.", + ) + + # class Config: + # pass + # # Galaxy Report/Page response can contain many extra_rendering_data + # # Allow any other extra fields + # extra = Extra.allow class InvocationUpdatePayload(Model): @@ -514,11 +556,7 @@ class InvocationOutputCollection(InvocationIOBase): ) -<<<<<<< HEAD -class WorkflowInvocationCollectionView(Model, WithModelClass): -======= class WorkflowInvocationBaseResponse(Model): ->>>>>>> Refactor pydantic model to enable reuse id: EncodedDatabaseIdField = InvocationIdField create_time: datetime = CreateTimeField update_time: datetime = UpdateTimeField From 11a5b8a3723fce3a98f7c7938d98671eca9b400e Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 2 Jan 2024 20:06:52 +0100 Subject: [PATCH 18/34] Rename WorkFlowInvocationResponse models --- lib/galaxy/schema/invocation.py | 4 ++-- lib/galaxy/webapps/galaxy/api/workflows.py | 28 ++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index bed5bdd23312..454e83d218ad 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -581,7 +581,7 @@ class WorkflowInvocationBaseResponse(Model): ) -class WorkflowInvocationResponse(WorkflowInvocationBaseResponse): +class WorkflowInvocationElementView(WorkflowInvocationBaseResponse): steps: List[InvocationStep] = Field( default=Required, title="Steps", description="Steps of the workflow invocation." ) @@ -604,7 +604,7 @@ class WorkflowInvocationResponse(WorkflowInvocationBaseResponse): ) -class IndexWorkflowInvocationResponse(WorkflowInvocationBaseResponse): +class WorkflowInvocationCollectionView(WorkflowInvocationBaseResponse): steps: Optional[List[InvocationStep]] = Field( default=None, title="Steps", description="Steps of the workflow invocation." ) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 3eb46a1b4521..0c207fcfd0ad 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -53,7 +53,6 @@ from galaxy.schema.invocation import ( CreateInvocationFromStore, CreateInvocationsFromStorePayload, - IndexWorkflowInvocationResponse, InvocationJobsResponse, InvocationMessageResponseModel, InvocationReport, @@ -64,7 +63,8 @@ InvocationStepJobsResponseJobModel, InvocationStepJobsResponseStepModel, InvocationUpdatePayload, - WorkflowInvocationResponse, + WorkflowInvocationCollectionView, + WorkflowInvocationElementView, ) from galaxy.schema.schema import ( AsyncFile, @@ -1233,7 +1233,7 @@ def create_invocations_from_store( self, payload: Annotated[CreateInvocationsFromStorePayload, CreateInvocationsFromStoreBody], trans: ProvidesHistoryContext = DependsOnTrans, - ) -> List[IndexWorkflowInvocationResponse]: + ) -> List[WorkflowInvocationCollectionView]: """ Input can be an archive describing a Galaxy model store containing an workflow invocation - for instance one created with with write_store @@ -1242,7 +1242,7 @@ def create_invocations_from_store( create_payload = CreateInvocationFromStore(**payload.dict()) serialization_params = InvocationSerializationParams(**payload.dict()) invocations = self.invocations_service.create_from_store(trans, create_payload, serialization_params) - return [IndexWorkflowInvocationResponse(**invocation) for invocation in invocations] + return [WorkflowInvocationCollectionView(**invocation) for invocation in invocations] @router.get( "/api/invocations", @@ -1260,7 +1260,7 @@ def index_invocations( view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, - ) -> List[IndexWorkflowInvocationResponse]: + ) -> List[WorkflowInvocationCollectionView]: """If workflow_id is supplied (either via URL or query parameter) it should be an encoded StoredWorkflow id and returned invocations will be restricted to that workflow. history_id (an encoded History id) can be used to further restrict the @@ -1282,7 +1282,7 @@ def index_invocations( ) invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) response.headers["total_matches"] = str(total_matches) - return [IndexWorkflowInvocationResponse(**invocation) for invocation in invocations] + return [WorkflowInvocationCollectionView(**invocation) for invocation in invocations] @router.get( "/api/workflows/{workflow_id}/invocations", @@ -1300,7 +1300,7 @@ def index_workflow_invocations( view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, - ) -> List[IndexWorkflowInvocationResponse]: + ) -> List[WorkflowInvocationCollectionView]: """An alias for GET '/api/invocations'""" invocations = self.index_invocations( response=response, @@ -1355,11 +1355,12 @@ def show_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationResponse: + ) -> WorkflowInvocationElementView: serialization_params = InvocationSerializationParams( step_details=step_details, legacy_job_state=legacy_job_state ) - return self.invocations_service.show(trans, invocation_id, serialization_params, eager=True) + rval = self.invocations_service.show(trans, invocation_id, serialization_params, eager=True) + return WorkflowInvocationElementView(**rval) @router.get( "/api/workflows/{workflow_id}/invocations/{invocation_id}", @@ -1377,7 +1378,7 @@ def show_workflow_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationResponse: + ) -> WorkflowInvocationElementView: """An alias for `GET /api/invocations/{invocation_id}`. `workflow_id` is ignored.""" return self.show_invocation( trans=trans, invocation_id=invocation_id, step_details=step_details, legacy_job_state=legacy_job_state @@ -1390,11 +1391,12 @@ def cancel_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationResponse: + ) -> WorkflowInvocationElementView: serialization_params = InvocationSerializationParams( step_details=step_details, legacy_job_state=legacy_job_state ) - return self.invocations_service.cancel(trans, invocation_id, serialization_params) + rval = self.invocations_service.cancel(trans, invocation_id, serialization_params) + return WorkflowInvocationElementView(**rval) @router.delete( "/api/workflows/{workflow_id}/invocations/{invocation_id}", summary="Cancel the specified workflow invocation." @@ -1411,7 +1413,7 @@ def cancel_workflow_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationResponse: + ) -> WorkflowInvocationElementView: """An alias for `DELETE /api/invocations/{invocation_id}`. `workflow_id` is ignored.""" return self.cancel_invocation( From e02eee54ebc500b1c48b20143a66d831d2697f73 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sat, 6 Jan 2024 13:13:25 +0100 Subject: [PATCH 19/34] Add missing query params for index_invocations operations --- lib/galaxy/webapps/galaxy/api/workflows.py | 91 +++++++++++++++++++--- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 0c207fcfd0ad..24f3e276fedb 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -69,6 +69,7 @@ from galaxy.schema.schema import ( AsyncFile, AsyncTaskResultSummary, + InvocationSortByEnum, SetSlugPayload, ShareWithPayload, ShareWithStatus, @@ -1177,12 +1178,19 @@ def get_workflow_menu( ), ] -# TODO rename? - this is already defined in jobs.py +WorkflowIdQueryParam = Annotated[ + Optional[DecodedDatabaseIdField], + Query( + title="Workflow ID", + description="Return only invocations for this Workflow ID", + ), +] + HistoryIdQueryParam = Annotated[ Optional[DecodedDatabaseIdField], Query( title="History ID", - description="Optional identifier of a History. Use it to restrict the search within a particular History.", + description="Return only invocations for this History ID", ), ] @@ -1190,7 +1198,7 @@ def get_workflow_menu( Optional[DecodedDatabaseIdField], Query( title="Job ID", - description="The encoded database identifier of the Job.", + description="Return only invocations for this Job ID", ), ] @@ -1198,15 +1206,56 @@ def get_workflow_menu( Optional[DecodedDatabaseIdField], Query( title="User ID", - description="The encoded database identifier of the User.", + description="Return invocations for this User ID.", ), ] -WorkflowIdQueryParam = Annotated[ - Optional[DecodedDatabaseIdField], +InvocationsSortByQueryParam = Annotated[ + Optional[InvocationSortByEnum], Query( - title="Workflow ID", - description="Return only invocations for this Workflow ID", + title="Sort By", + description="Sort Workflow Invocations by this attribute", + ), +] + +InvocationsSortDescQueryParam = Annotated[ + bool, + Query( + title="Sort Descending", + description="Sort in descending order?", + ), +] + +InvocationsIncludeTerminalQueryParam = Annotated[ + Optional[bool], + Query( + title="Include Terminal", + description="Set to false to only include terminal Invocations.", + ), +] + +InvocationsLimitQueryParam = Annotated[ + Optional[int], + Query( + title="Limit", + description="Limit the number of invocations to return.", + ), +] + +InvocationsOffsetQueryParam = Annotated[ + Optional[int], + Query( + title="Offset", + description="Number of invocations to skip.", + ), +] + + +InvocationsInstanceQueryParam = Annotated[ + Optional[bool], + Query( + title="Instance", + description="Is provided workflow id for Workflow instead of StoredWorkflow?", ), ] @@ -1256,7 +1305,12 @@ def index_invocations( history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, - instance: Annotated[Optional[bool], InstanceQueryParam] = False, + sort_by: Annotated[Optional[InvocationSortByEnum], InvocationsSortByQueryParam] = None, + sort_desc: Annotated[Optional[bool], InvocationsSortDescQueryParam] = False, + include_terminal: Annotated[Optional[bool], InvocationsIncludeTerminalQueryParam] = True, + limit: Annotated[Optional[int], InvocationsLimitQueryParam] = None, + offset: Annotated[Optional[int], InvocationsOffsetQueryParam] = None, + instance: Annotated[Optional[bool], InvocationsInstanceQueryParam] = False, view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, @@ -1270,6 +1324,11 @@ def index_invocations( :raises: exceptions.MessageException, exceptions.ObjectNotFound """ invocation_payload = InvocationIndexPayload( + sort_by=sort_by, + sort_desc=sort_desc, + include_terminal=include_terminal, + limit=limit, + offset=offset, instance=instance, ) invocation_payload.workflow_id = workflow_id @@ -1296,7 +1355,12 @@ def index_workflow_invocations( history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, - instance: Annotated[Optional[bool], InstanceQueryParam] = False, + sort_by: Annotated[Optional[InvocationSortByEnum], InvocationsSortByQueryParam] = None, + sort_desc: Annotated[Optional[bool], InvocationsSortDescQueryParam] = False, + include_terminal: Annotated[Optional[bool], InvocationsIncludeTerminalQueryParam] = True, + limit: Annotated[Optional[int], InvocationsLimitQueryParam] = None, + offset: Annotated[Optional[int], InvocationsOffsetQueryParam] = None, + instance: Annotated[Optional[bool], InvocationsInstanceQueryParam] = False, view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, @@ -1304,13 +1368,18 @@ def index_workflow_invocations( """An alias for GET '/api/invocations'""" invocations = self.index_invocations( response=response, + workflow_id=workflow_id, history_id=history_id, job_id=job_id, user_id=user_id, + sort_by=sort_by, + sort_desc=sort_desc, + include_terminal=include_terminal, + limit=limit, + offset=offset, instance=instance, view=view, step_details=step_details, - workflow_id=workflow_id, trans=trans, ) return invocations From 5a8a89a46274062c57b9617fc6a63ae6c69598a6 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sat, 6 Jan 2024 13:49:32 +0100 Subject: [PATCH 20/34] Remove testing deprecated route --- lib/galaxy_test/api/test_workflows.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/galaxy_test/api/test_workflows.py b/lib/galaxy_test/api/test_workflows.py index aa0d83b3c9e5..68386bfe4792 100644 --- a/lib/galaxy_test/api/test_workflows.py +++ b/lib/galaxy_test/api/test_workflows.py @@ -7102,9 +7102,9 @@ def test_invocations_accessible_imported_workflow(self): self._assert_status_code_is(other_import_response, 200) other_id = other_import_response.json()["id"] workflow_request, history_id, _ = self._setup_workflow_run(workflow_id=other_id) - response = self._get(f"workflows/{other_id}/usage") - self._assert_status_code_is(response, 200) - assert len(response.json()) == 0 + # response = self._get(f"workflows/{other_id}/usage") + # self._assert_status_code_is(response, 200) + # assert len(response.json()) == 0 run_workflow_response = self.workflow_populator.invoke_workflow_raw( workflow_id, workflow_request, assert_ok=True ) @@ -7118,9 +7118,9 @@ def test_invocations_accessible_published_workflow(self): workflow_id = self.workflow_populator.simple_workflow("test_usage", publish=True) with self._different_user(): workflow_request, history_id, _ = self._setup_workflow_run(workflow_id=workflow_id) - response = self._get(f"workflows/{workflow_id}/usage") - self._assert_status_code_is(response, 200) - assert len(response.json()) == 0 + # response = self._get(f"workflows/{workflow_id}/usage") + # self._assert_status_code_is(response, 200) + # assert len(response.json()) == 0 run_workflow_response = self.workflow_populator.invoke_workflow_raw( workflow_id, workflow_request, assert_ok=True ) @@ -7133,9 +7133,9 @@ def test_invocations_accessible_published_workflow(self): def test_invocations_not_accessible_by_different_user_for_published_workflow(self): workflow_id = self.workflow_populator.simple_workflow("test_usage", publish=True) workflow_request, history_id, _ = self._setup_workflow_run(workflow_id=workflow_id) - response = self._get(f"workflows/{workflow_id}/usage") - self._assert_status_code_is(response, 200) - assert len(response.json()) == 0 + # response = self._get(f"workflows/{workflow_id}/usage") + # self._assert_status_code_is(response, 200) + # assert len(response.json()) == 0 run_workflow_response = self.workflow_populator.invoke_workflow_raw( workflow_id, workflow_request, assert_ok=True ) From 48b355f266d2116de140c37a9aebb27fdd22d19f Mon Sep 17 00:00:00 2001 From: Tillman Date: Sun, 7 Jan 2024 16:05:20 +0100 Subject: [PATCH 21/34] Refine pydantic models --- lib/galaxy/schema/invocation.py | 83 +++++++-------------------------- 1 file changed, 17 insertions(+), 66 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 454e83d218ad..81715820f3b3 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -305,15 +305,6 @@ class InvocationStepState(str, Enum): # FAILED = 'failed', TODO: implement and expose -class ExtendedInvocationStepState(str, Enum): - NEW = "new" # Brand new workflow invocation step - READY = "ready" # Workflow invocation step ready for another iteration of scheduling. - SCHEDULED = "scheduled" # Workflow invocation step has been scheduled. - # CANCELLED = 'cancelled', TODO: implement and expose - # FAILED = 'failed', TODO: implement and expose - OK = "ok" # Workflow invocation step has completed successfully - TODO: is this a correct description? - - class InvocationStepOutput(Model): src: INVOCATION_STEP_OUTPUT_SRC = Field( literal_to_value(INVOCATION_STEP_OUTPUT_SRC), @@ -351,37 +342,22 @@ class InvocationStep(Model, WithModelClass): model_class: INVOCATION_STEP_MODEL_CLASS = ModelClassField(INVOCATION_STEP_MODEL_CLASS) id: Annotated[EncodedDatabaseIdField, Field(..., title="Invocation Step ID")] update_time: Optional[datetime] = schema.UpdateTimeField - job_id: Optional[ - Annotated[ - EncodedDatabaseIdField, - Field( - default=None, - title="Job ID", - description="The encoded ID of the job associated with this workflow invocation step.", - ), - ] - ] - workflow_step_id: Annotated[ - EncodedDatabaseIdField, - Field( - ..., - title="Workflow step ID", - description="The encoded ID of the workflow step associated with this workflow invocation step.", - ), - ] - subworkflow_invocation_id: Optional[ - Annotated[ - EncodedDatabaseIdField, - Field( - default=None, - title="Subworkflow invocation ID", - description="The encoded ID of the subworkflow invocation.", - ), - ] - ] - # TODO The state can differ from InvocationStepState is this intended? - # InvocationStepState is equal to the states attribute of the WorkflowInvocationStep class - state: Optional[ExtendedInvocationStepState] = Field( + job_id: Optional[EncodedDatabaseIdField] = Field( + default=None, + title="Job ID", + description="The encoded ID of the job associated with this workflow invocation step.", + ) + workflow_step_id: EncodedDatabaseIdField = Field( + ..., + title="Workflow step ID", + description="The encoded ID of the workflow step associated with this workflow invocation step.", + ) + subworkflow_invocation_id: Optional[EncodedDatabaseIdField] = Field( + default=None, + title="Subworkflow invocation ID", + description="The encoded ID of the subworkflow invocation.", + ) + state: Optional[Union[InvocationStepState, JobState]] = Field( default=None, title="State of the invocation step", description="Describes where in the scheduling process the workflow invocation step is.", @@ -493,12 +469,6 @@ class InvocationReport(Model, WithModelClass): description="Other invocations associated with the invocation.", ) - # class Config: - # pass - # # Galaxy Report/Page response can contain many extra_rendering_data - # # Allow any other extra fields - # extra = Extra.allow - class InvocationUpdatePayload(Model): action: bool = InvocationStepActionField @@ -605,26 +575,7 @@ class WorkflowInvocationElementView(WorkflowInvocationBaseResponse): class WorkflowInvocationCollectionView(WorkflowInvocationBaseResponse): - steps: Optional[List[InvocationStep]] = Field( - default=None, title="Steps", description="Steps of the workflow invocation." - ) - inputs: Optional[Dict[str, InvocationInput]] = Field( - default=None, title="Inputs", description="Input datasets/dataset collections of the workflow invocation." - ) - input_step_parameters: Optional[Dict[str, InvocationInputParameter]] = Field( - default=None, title="Input step parameters", description="Input step parameters of the workflow invocation." - ) - outputs: Optional[Dict[str, InvocationOutput]] = Field( - default=None, title="Outputs", description="Output datasets of the workflow invocation." - ) - output_collections: Optional[Dict[str, InvocationOutputCollection]] = Field( - default=None, - title="Output collections", - description="Output dataset collections of the workflow invocation.", - ) - output_values: Optional[Dict[str, Any]] = Field( - default=None, title="Output values", description="Output values of the workflow invocation." - ) + pass class WorkflowInvocationResponse(RootModel): From 44d909a1ee3b29c9cf334b6b8d5292bdab81cfa2 Mon Sep 17 00:00:00 2001 From: Tillman Date: Thu, 11 Jan 2024 15:24:28 +0100 Subject: [PATCH 22/34] Resolve issue with pydnatic 2 and new models --- lib/galaxy/schema/invocation.py | 28 +++++++------------ lib/galaxy/webapps/galaxy/api/workflows.py | 22 +++++++-------- .../webapps/galaxy/services/invocations.py | 1 - 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 81715820f3b3..286eedafa721 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -526,7 +526,7 @@ class InvocationOutputCollection(InvocationIOBase): ) -class WorkflowInvocationBaseResponse(Model): +class WorkflowInvocationCollectionView(Model, WithModelClass): id: EncodedDatabaseIdField = InvocationIdField create_time: datetime = CreateTimeField update_time: datetime = UpdateTimeField @@ -544,17 +544,10 @@ class WorkflowInvocationBaseResponse(Model): ) state: InvocationState = Field(default=..., title="Invocation state", description="State of workflow invocation.") model_class: INVOCATION_MODEL_CLASS = ModelClassField(INVOCATION_MODEL_CLASS) - messages: List[InvocationMessageResponseUnion] = Field( - default=Required, - title="Messages", - description="A list of messages about why the invocation did not succeed.", - ) -class WorkflowInvocationElementView(WorkflowInvocationBaseResponse): - steps: List[InvocationStep] = Field( - default=Required, title="Steps", description="Steps of the workflow invocation." - ) +class WorkflowInvocationElementView(WorkflowInvocationCollectionView): + steps: List[InvocationStep] = Field(default=..., title="Steps", description="Steps of the workflow invocation.") inputs: Dict[str, InvocationInput] = Field( default=..., title="Inputs", description="Input datasets/dataset collections of the workflow invocation." ) @@ -572,10 +565,11 @@ class WorkflowInvocationElementView(WorkflowInvocationBaseResponse): output_values: Dict[str, Any] = Field( default=..., title="Output values", description="Output values of the workflow invocation." ) - - -class WorkflowInvocationCollectionView(WorkflowInvocationBaseResponse): - pass + messages: List[InvocationMessageResponseUnion] = Field( + default=..., + title="Messages", + description="A list of messages about why the invocation did not succeed.", + ) class WorkflowInvocationResponse(RootModel): @@ -614,10 +608,8 @@ class InvocationStepJobsResponseCollectionJobsModel(InvocationJobsSummaryBaseMod class CreateInvocationFromStore(StoreContentSource): # TODO - add proper description - history_id: EncodedDatabaseIdField = Field(default=Required, title="History ID", description="") - - class Config: - extra = Extra.allow + history_id: EncodedDatabaseIdField = Field(default=..., title="History ID", description="") + model_config = ConfigDict(extra="allow") class InvocationSerializationView(str, Enum): diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 24f3e276fedb..83a715bc79f0 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -23,7 +23,6 @@ ) from gxformat2._yaml import ordered_dump from markupsafe import escape -from pydantic import Required from starlette.responses import StreamingResponse from typing_extensions import Annotated @@ -65,6 +64,7 @@ InvocationUpdatePayload, WorkflowInvocationCollectionView, WorkflowInvocationElementView, + WorkflowInvocationResponse, ) from galaxy.schema.schema import ( AsyncFile, @@ -1262,7 +1262,7 @@ def get_workflow_menu( CreateInvocationsFromStoreBody = Annotated[ CreateInvocationsFromStorePayload, Body( - default=Required, + default=..., title="Create invocations from store", description="The values and serialization parameters for creating invocations from a supplied model store.", ), @@ -1288,8 +1288,8 @@ def create_invocations_from_store( workflow invocation - for instance one created with with write_store or prepare_store_download endpoint. """ - create_payload = CreateInvocationFromStore(**payload.dict()) - serialization_params = InvocationSerializationParams(**payload.dict()) + create_payload = CreateInvocationFromStore(**payload.model_dump()) + serialization_params = InvocationSerializationParams(**payload.model_dump()) invocations = self.invocations_service.create_from_store(trans, create_payload, serialization_params) return [WorkflowInvocationCollectionView(**invocation) for invocation in invocations] @@ -1424,12 +1424,11 @@ def show_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationElementView: + ) -> WorkflowInvocationResponse: serialization_params = InvocationSerializationParams( step_details=step_details, legacy_job_state=legacy_job_state ) - rval = self.invocations_service.show(trans, invocation_id, serialization_params, eager=True) - return WorkflowInvocationElementView(**rval) + return self.invocations_service.show(trans, invocation_id, serialization_params, eager=True) @router.get( "/api/workflows/{workflow_id}/invocations/{invocation_id}", @@ -1447,7 +1446,7 @@ def show_workflow_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationElementView: + ) -> WorkflowInvocationResponse: """An alias for `GET /api/invocations/{invocation_id}`. `workflow_id` is ignored.""" return self.show_invocation( trans=trans, invocation_id=invocation_id, step_details=step_details, legacy_job_state=legacy_job_state @@ -1460,12 +1459,11 @@ def cancel_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationElementView: + ) -> WorkflowInvocationResponse: serialization_params = InvocationSerializationParams( step_details=step_details, legacy_job_state=legacy_job_state ) - rval = self.invocations_service.cancel(trans, invocation_id, serialization_params) - return WorkflowInvocationElementView(**rval) + return self.invocations_service.cancel(trans, invocation_id, serialization_params) @router.delete( "/api/workflows/{workflow_id}/invocations/{invocation_id}", summary="Cancel the specified workflow invocation." @@ -1482,7 +1480,7 @@ def cancel_workflow_invocation( trans: ProvidesUserContext = DependsOnTrans, step_details: StepDetailQueryParam = False, legacy_job_state: LegacyJobStateQueryParam = False, - ) -> WorkflowInvocationElementView: + ) -> WorkflowInvocationResponse: """An alias for `DELETE /api/invocations/{invocation_id}`. `workflow_id` is ignored.""" return self.cancel_invocation( diff --git a/lib/galaxy/webapps/galaxy/services/invocations.py b/lib/galaxy/webapps/galaxy/services/invocations.py index ecf50f1b5ced..8c248cbc7d82 100644 --- a/lib/galaxy/webapps/galaxy/services/invocations.py +++ b/lib/galaxy/webapps/galaxy/services/invocations.py @@ -35,7 +35,6 @@ from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.invocation import ( CreateInvocationFromStore, - InvocationMessageResponseModel, InvocationSerializationParams, InvocationSerializationView, InvocationStep, From 0d375fd413ad83e7a0436829c4a693384566bc77 Mon Sep 17 00:00:00 2001 From: Tillman Date: Thu, 11 Jan 2024 15:46:36 +0100 Subject: [PATCH 23/34] Revert some changes --- lib/galaxy/schema/invocation.py | 9 +++++---- lib/galaxy/webapps/galaxy/api/workflows.py | 2 +- lib/galaxy/webapps/galaxy/services/invocations.py | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 286eedafa721..e2755539ba17 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -603,7 +603,7 @@ class InvocationStepJobsResponseJobModel(InvocationJobsSummaryBaseModel): class InvocationStepJobsResponseCollectionJobsModel(InvocationJobsSummaryBaseModel): - model: IMPLICIT_COLLECTION_JOBS_MODEL_CLASS = ModelClassField(IMPLICIT_COLLECTION_JOBS_MODEL_CLASS) + model: IMPLICIT_COLLECTION_JOBS_MODEL_CLASS class CreateInvocationFromStore(StoreContentSource): @@ -617,7 +617,7 @@ class InvocationSerializationView(str, Enum): collection = "collection" -class InvocationSerializationParams(Model): +class InvocationSerializationParams(BaseModel): """Contains common parameters for customizing model serialization.""" view: Optional[InvocationSerializationView] = Field( @@ -627,7 +627,7 @@ class InvocationSerializationParams(Model): "The name of the view used to serialize this item. " "This will return a predefined set of attributes of the item." ), - example="element", + examples=["element"], ) step_details: bool = Field( default=False, @@ -640,7 +640,8 @@ class InvocationSerializationParams(Model): This will also produce one step per job in mapping jobs to mimic the older behavior with respect to collections. Partially scheduled steps may provide incomplete information and the listed steps outputs are not the mapped over step outputs but the individual job outputs.""", - deprecated=True, + # TODO: also deprecate on python side, https://github.com/pydantic/pydantic/issues/2255 + json_schema_extra={"deprecated": True}, ) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 83a715bc79f0..7e33c9f87f40 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -63,7 +63,6 @@ InvocationStepJobsResponseStepModel, InvocationUpdatePayload, WorkflowInvocationCollectionView, - WorkflowInvocationElementView, WorkflowInvocationResponse, ) from galaxy.schema.schema import ( @@ -1284,6 +1283,7 @@ def create_invocations_from_store( trans: ProvidesHistoryContext = DependsOnTrans, ) -> List[WorkflowInvocationCollectionView]: """ + TODO - expose anonymous Input can be an archive describing a Galaxy model store containing an workflow invocation - for instance one created with with write_store or prepare_store_download endpoint. diff --git a/lib/galaxy/webapps/galaxy/services/invocations.py b/lib/galaxy/webapps/galaxy/services/invocations.py index 8c248cbc7d82..72332a578ae9 100644 --- a/lib/galaxy/webapps/galaxy/services/invocations.py +++ b/lib/galaxy/webapps/galaxy/services/invocations.py @@ -156,12 +156,12 @@ def show_invocation_step_jobs_summary(self, trans, invocation_id) -> List[Dict[s for job_source_type, job_source_id, _ in invocation_job_source_iter(trans.sa_session, invocation_id): ids.append(job_source_id) types.append(job_source_type) - return [s for s in fetch_job_states(trans.sa_session, ids, types)] + return fetch_job_states(trans.sa_session, ids, types) def show_invocation_jobs_summary(self, trans, invocation_id) -> Dict[str, Any]: ids = [invocation_id] types = ["WorkflowInvocation"] - return [s for s in fetch_job_states(trans.sa_session, ids, types)][0] + return fetch_job_states(trans.sa_session, ids, types)[0] def prepare_store_download( self, trans, invocation_id: DecodedDatabaseIdField, payload: PrepareStoreDownloadPayload From 7719c5b16ab74b89b110052f9e0e02c5188b1687 Mon Sep 17 00:00:00 2001 From: Tillman Date: Thu, 11 Jan 2024 15:49:03 +0100 Subject: [PATCH 24/34] Regenerate the client schema --- client/src/api/schema/schema.ts | 284 +++++++++++++++++++++++++++----- 1 file changed, 242 insertions(+), 42 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 0bdc84809f33..5bb7821969cd 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -908,6 +908,26 @@ export interface paths { /** Prepare history for export-style download and write to supplied URI. */ post: operations["write_store_api_histories__history_id__write_store_post"]; }; + "/api/invocations": { + /** + * Get the list of a user's workflow invocations. + * @description If workflow_id is supplied (either via URL or query parameter) it should be an + * encoded StoredWorkflow id and returned invocations will be restricted to that + * workflow. history_id (an encoded History id) can be used to further restrict the + * query. If neither a workflow_id or history_id is supplied, all the current user's + * workflow invocations will be indexed (as determined by the invocation being + * executed on one of the user's histories) + * :raises: exceptions.MessageException, exceptions.ObjectNotFound + */ + get: operations["index_invocations_api_invocations_get"]; + }; + "/api/invocations/from_store": { + /** + * Create Invocations From Store + * @description Create invocation(s) from a supplied model store. + */ + post: operations["create_invocations_from_store_api_invocations_from_store_post"]; + }; "/api/invocations/steps/{step_id}": { /** Show details of workflow invocation step. */ get: operations["step_api_invocations_steps__step_id__get"]; @@ -1788,6 +1808,13 @@ export interface paths { */ put: operations["enable_link_access_api_workflows__workflow_id__enable_link_access_put"]; }; + "/api/workflows/{workflow_id}/invocations": { + /** + * Get the list of a user's workflow invocations. + * @description An alias for GET '/api/invocations' + */ + get: operations["index_invocations_api_workflows__workflow_id__invocations_get"]; + }; "/api/workflows/{workflow_id}/invocations/{invocation_id}": { /** * Get detailed description of a workflow invocation. @@ -3022,6 +3049,41 @@ export interface components { /** Store Dict */ store_dict?: Record | null; }; + /** CreateInvocationsFromStorePayload */ + CreateInvocationsFromStorePayload: { + /** + * History ID + * @example 0123456789ABCDEF + */ + history_id: string; + /** + * Legacy Job State + * @deprecated + * @description Populate the invocation step state with the job state instead of the invocation step state. + * This will also produce one step per job in mapping jobs to mimic the older behavior with respect to collections. + * Partially scheduled steps may provide incomplete information and the listed steps outputs + * are not the mapped over step outputs but the individual job outputs. + * @default false + */ + legacy_job_state?: boolean; + model_store_format?: components["schemas"]["ModelStoreFormat"] | null; + /** + * Include step details + * @description Include details for individual invocation steps and populate a steps attribute in the resulting dictionary + * @default false + */ + step_details?: boolean; + /** Store Content Uri */ + store_content_uri?: string | null; + /** Store Dict */ + store_dict?: Record | null; + /** + * View + * @description The name of the view used to serialize this item. This will return a predefined set of attributes of the item. + */ + view?: components["schemas"]["InvocationSerializationView"] | null; + [key: string]: unknown | undefined; + }; /** CreateLibrariesFromStore */ CreateLibrariesFromStore: { model_store_format?: components["schemas"]["ModelStoreFormat"] | null; @@ -4559,11 +4621,6 @@ export interface components { }; /** ExportTaskListResponse */ ExportTaskListResponse: components["schemas"]["ObjectExportTaskResponse"][]; - /** - * ExtendedInvocationStepState - * @enum {string} - */ - ExtendedInvocationStepState: "new" | "ready" | "scheduled" | "ok"; /** ExtraFileEntry */ ExtraFileEntry: { /** @description The class of this entry, either File or Directory. */ @@ -6962,6 +7019,11 @@ export interface components { * @description Report describing workflow invocation */ InvocationReport: { + /** + * Errors + * @description Errors associated with the invocation. + */ + errors?: Record | null; /** * Galaxy Version * @description The version of Galaxy this object was generated with. @@ -6972,6 +7034,21 @@ export interface components { * @description The version of Galaxy this object was generated with. */ generate_version?: string | null; + /** + * Histories + * @description Histories associated with the invocation. + */ + histories?: Record | null; + /** + * History dataset collections + * @description History dataset collections associated with the invocation. + */ + history_dataset_collections?: Record | null; + /** + * History datasets + * @description History datasets associated with the invocation. + */ + history_datasets?: Record | null; /** * Workflow ID * @description The workflow this invocation has been triggered for. @@ -6981,13 +7058,21 @@ export interface components { /** * Markdown * @description Raw galaxy-flavored markdown contents of the report. - * @default */ invocation_markdown?: string | null; + /** + * Invocations + * @description Other invocations associated with the invocation. + */ + invocations?: Record | null; + /** + * Jobs + * @description Jobs associated with the invocation. + */ + jobs?: Record | null; /** * Markdown * @description Raw galaxy-flavored markdown contents of the report. - * @default */ markdown?: string | null; /** @@ -7013,8 +7098,22 @@ export interface components { * @description The name of the user who owns this report. */ username: string; - [key: string]: unknown | undefined; + /** + * Workflows + * @description Workflows associated with the invocation. + */ + workflows?: Record | null; }; + /** + * InvocationSerializationView + * @enum {string} + */ + InvocationSerializationView: "element" | "collection"; + /** + * InvocationSortByEnum + * @enum {string} + */ + InvocationSortByEnum: "create_time" | "update_time" | "None"; /** * InvocationState * @enum {string} @@ -7035,8 +7134,11 @@ export interface components { * @example 0123456789ABCDEF */ id: string; - /** Job Id */ - job_id: string | null; + /** + * Job ID + * @description The encoded ID of the job associated with this workflow invocation step. + */ + job_id?: string | null; /** * Jobs * @description Jobs associated with the workflow invocation step. @@ -7074,9 +7176,12 @@ export interface components { * State of the invocation step * @description Describes where in the scheduling process the workflow invocation step is. */ - state?: components["schemas"]["ExtendedInvocationStepState"] | null; - /** Subworkflow Invocation Id */ - subworkflow_invocation_id: string | null; + state?: components["schemas"]["InvocationStepState"] | components["schemas"]["JobState"] | null; + /** + * Subworkflow invocation ID + * @description The encoded ID of the subworkflow invocation. + */ + subworkflow_invocation_id?: string | null; /** * Update Time * @description The last time and date this item was updated. @@ -7214,6 +7319,11 @@ export interface components { */ uuid?: string | null; }; + /** + * InvocationStepState + * @enum {string} + */ + InvocationStepState: "new" | "ready" | "scheduled"; /** InvocationUnexpectedFailureResponse */ InvocationUnexpectedFailureResponse: { /** @@ -11292,7 +11402,6 @@ export interface operations { * configuration settings are returned. */ parameters?: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -11714,7 +11823,6 @@ export interface operations { /** Search datasets or collections using a query system. */ parameters?: { /** @description Optional identifier of a History. Use it to restrict the search within a particular History. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -11800,7 +11908,6 @@ export interface operations { parameters: { /** @description The type of information about the dataset to be requested. */ /** @description The type of information about the dataset to be requested. Each of these values may require additional parameters in the request and may return different responses. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { hda_ldda?: components["schemas"]["DatasetSourceType"]; @@ -11900,7 +12007,6 @@ export interface operations { * **Note**: `view` and `keys` are also available to control the serialization of the dataset. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -13706,7 +13812,6 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { all?: boolean | null; @@ -13749,7 +13854,6 @@ export interface operations { * @description The new history can also be copied form a existing history or imported from an archive or URL. */ parameters?: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -13792,7 +13896,6 @@ export interface operations { * Archived histories are histories are not part of the active histories of the user but they can be accessed using this endpoint. */ parameters?: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -13864,7 +13967,6 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { all?: boolean | null; @@ -13903,7 +14005,6 @@ export interface operations { undelete_api_histories_deleted__history_id__undelete_post: { /** Restores a deleted history with the given ID (that hasn't been purged). */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -13939,7 +14040,6 @@ export interface operations { create_from_store_api_histories_from_store_post: { /** Create histories from a model store. */ parameters?: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14004,7 +14104,6 @@ export interface operations { show_recent_api_histories_most_recently_used_get: { /** Returns the most recently used history of the user. */ parameters?: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14041,7 +14140,6 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { q?: string[] | null; @@ -14154,7 +14252,6 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { q?: string[] | null; @@ -14192,7 +14289,6 @@ export interface operations { history_api_histories__history_id__get: { /** Returns the history with the given ID. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14228,7 +14324,6 @@ export interface operations { update_api_histories__history_id__put: { /** Updates the values for the history with the given ID. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14269,7 +14364,6 @@ export interface operations { delete_api_histories__history_id__delete: { /** Marks the history with the given ID as deleted. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { purge?: boolean; @@ -14462,7 +14556,6 @@ export interface operations { * @description Whether to return visible or hidden datasets only. Leave unset for both. */ /** @description Whether to return only shareable or not shareable datasets. Leave unset for both. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -14519,7 +14612,6 @@ export interface operations { * will be made to the items. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14562,7 +14654,6 @@ export interface operations { */ parameters: { /** @description The type of the target history element. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"] | null; @@ -15153,7 +15244,6 @@ export interface operations { parameters: { /** @description The type of the target history element. */ /** @description This value can be used to broadly restrict the magnitude of the number of elements returned via the API for large collections. The number of actual elements returned may be "a bit" more than this number or "a lot" less - varying on the depth of nesting, balance of nesting at each level, and size of target collection. The consumer of this API should not expect a stable number or pre-calculable number of elements to be produced given this parameter - the only promise is that this API will not respond with an order of magnitude more elements estimated with this value. The UI uses this parameter to fetch a "balanced" concept of the "start" of large collections at every depth of the collection. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"]; @@ -15200,7 +15290,6 @@ export interface operations { */ parameters: { /** @description The type of the target history element. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"]; @@ -15264,7 +15353,6 @@ export interface operations { * @deprecated * @description Whether to stop the creating job if all outputs of the job have been deleted. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"]; @@ -15376,7 +15464,6 @@ export interface operations { * @description Whether to return visible or hidden datasets only. Leave unset for both. */ /** @description Whether to return only shareable or not shareable datasets. Leave unset for both. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -15433,7 +15520,6 @@ export interface operations { * @description Create a new `HDA` or `HDCA` in the given History. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -15491,7 +15577,6 @@ export interface operations { */ parameters: { /** @description This value can be used to broadly restrict the magnitude of the number of elements returned via the API for large collections. The number of actual elements returned may be "a bit" more than this number or "a lot" less - varying on the depth of nesting, balance of nesting at each level, and size of target collection. The consumer of this API should not expect a stable number or pre-calculable number of elements to be produced given this parameter - the only promise is that this API will not respond with an order of magnitude more elements estimated with this value. The UI uses this parameter to fetch a "balanced" concept of the "start" of large collections at every depth of the collection. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { fuzzy_count?: number | null; @@ -15537,7 +15622,6 @@ export interface operations { * @description Updates the values for the history content item with the given ``ID``. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -15601,7 +15685,6 @@ export interface operations { * @deprecated * @description Whether to stop the creating job if all outputs of the job have been deleted. */ - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { purge?: boolean | null; @@ -15772,7 +15855,6 @@ export interface operations { * or hand-crafted JSON dictionary. */ parameters: { - /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -16465,6 +16547,83 @@ export interface operations { }; }; }; + index_invocations_api_invocations_get: { + /** + * Get the list of a user's workflow invocations. + * @description If workflow_id is supplied (either via URL or query parameter) it should be an + * encoded StoredWorkflow id and returned invocations will be restricted to that + * workflow. history_id (an encoded History id) can be used to further restrict the + * query. If neither a workflow_id or history_id is supplied, all the current user's + * workflow invocations will be indexed (as determined by the invocation being + * executed on one of the user's histories) + * :raises: exceptions.MessageException, exceptions.ObjectNotFound + */ + parameters?: { + query?: { + workflow_id?: string | null; + history_id?: string | null; + job_id?: string | null; + user_id?: string | null; + sort_by?: components["schemas"]["InvocationSortByEnum"] | null; + sort_desc?: boolean | null; + include_terminal?: boolean | null; + limit?: number | null; + offset?: number | null; + instance?: boolean | null; + view?: components["schemas"]["InvocationSerializationView"] | null; + step_details?: boolean | null; + }; + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["WorkflowInvocationCollectionView"][]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + create_invocations_from_store_api_invocations_from_store_post: { + /** + * Create Invocations From Store + * @description Create invocation(s) from a supplied model store. + */ + parameters?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateInvocationsFromStorePayload"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["WorkflowInvocationCollectionView"][]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; step_api_invocations_steps__step_id__get: { /** Show details of workflow invocation step. */ parameters: { @@ -21294,6 +21453,48 @@ export interface operations { }; }; }; + index_invocations_api_workflows__workflow_id__invocations_get: { + /** + * Get the list of a user's workflow invocations. + * @description An alias for GET '/api/invocations' + */ + parameters: { + query?: { + history_id?: string | null; + job_id?: string | null; + user_id?: string | null; + sort_by?: components["schemas"]["InvocationSortByEnum"] | null; + sort_desc?: boolean | null; + include_terminal?: boolean | null; + limit?: number | null; + offset?: number | null; + instance?: boolean | null; + view?: components["schemas"]["InvocationSerializationView"] | null; + step_details?: boolean | null; + }; + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + path: { + workflow_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["WorkflowInvocationCollectionView"][]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; show_workflow_invocation_api_workflows__workflow_id__invocations__invocation_id__get: { /** * Get detailed description of a workflow invocation. @@ -22213,7 +22414,6 @@ export interface operations { header?: { "run-as"?: string | null; }; - /** @description The encoded database identifier of the Stored Workflow. */ path: { workflow_id: string; }; From ac7e7a86c2ac95852547b881f3088d6235d6104d Mon Sep 17 00:00:00 2001 From: Tillman Date: Thu, 11 Jan 2024 20:04:44 +0100 Subject: [PATCH 25/34] Resolve merge mistakes --- lib/galaxy/schema/invocation.py | 6 ++++-- lib/galaxy/webapps/galaxy/api/workflows.py | 12 +++++------- lib/galaxy/webapps/galaxy/services/invocations.py | 4 +--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index e2755539ba17..55c083edcbd6 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -28,6 +28,7 @@ from galaxy.schema import schema from galaxy.schema.fields import ( + DecodedDatabaseIdField, EncodedDatabaseIdField, literal_to_value, ModelClassField, @@ -608,7 +609,7 @@ class InvocationStepJobsResponseCollectionJobsModel(InvocationJobsSummaryBaseMod class CreateInvocationFromStore(StoreContentSource): # TODO - add proper description - history_id: EncodedDatabaseIdField = Field(default=..., title="History ID", description="") + history_id: DecodedDatabaseIdField = Field(default=..., title="History ID", description="") model_config = ConfigDict(extra="allow") @@ -646,4 +647,5 @@ class InvocationSerializationParams(BaseModel): class CreateInvocationsFromStorePayload(CreateInvocationFromStore, InvocationSerializationParams): - pass + # TODO - add proper description + history_id: str = Field(default=..., title="History ID", description="") diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 7e33c9f87f40..5e969e0f19b2 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -62,7 +62,6 @@ InvocationStepJobsResponseJobModel, InvocationStepJobsResponseStepModel, InvocationUpdatePayload, - WorkflowInvocationCollectionView, WorkflowInvocationResponse, ) from galaxy.schema.schema import ( @@ -1281,7 +1280,7 @@ def create_invocations_from_store( self, payload: Annotated[CreateInvocationsFromStorePayload, CreateInvocationsFromStoreBody], trans: ProvidesHistoryContext = DependsOnTrans, - ) -> List[WorkflowInvocationCollectionView]: + ) -> List[WorkflowInvocationResponse]: """ TODO - expose anonymous Input can be an archive describing a Galaxy model store containing an @@ -1290,8 +1289,7 @@ def create_invocations_from_store( """ create_payload = CreateInvocationFromStore(**payload.model_dump()) serialization_params = InvocationSerializationParams(**payload.model_dump()) - invocations = self.invocations_service.create_from_store(trans, create_payload, serialization_params) - return [WorkflowInvocationCollectionView(**invocation) for invocation in invocations] + return self.invocations_service.create_from_store(trans, create_payload, serialization_params) @router.get( "/api/invocations", @@ -1314,7 +1312,7 @@ def index_invocations( view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, - ) -> List[WorkflowInvocationCollectionView]: + ) -> List[WorkflowInvocationResponse]: """If workflow_id is supplied (either via URL or query parameter) it should be an encoded StoredWorkflow id and returned invocations will be restricted to that workflow. history_id (an encoded History id) can be used to further restrict the @@ -1341,7 +1339,7 @@ def index_invocations( ) invocations, total_matches = self.invocations_service.index(trans, invocation_payload, serialization_params) response.headers["total_matches"] = str(total_matches) - return [WorkflowInvocationCollectionView(**invocation) for invocation in invocations] + return invocations @router.get( "/api/workflows/{workflow_id}/invocations", @@ -1364,7 +1362,7 @@ def index_workflow_invocations( view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, trans: ProvidesUserContext = DependsOnTrans, - ) -> List[WorkflowInvocationCollectionView]: + ) -> List[WorkflowInvocationResponse]: """An alias for GET '/api/invocations'""" invocations = self.index_invocations( response=response, diff --git a/lib/galaxy/webapps/galaxy/services/invocations.py b/lib/galaxy/webapps/galaxy/services/invocations.py index 72332a578ae9..79912285c2ac 100644 --- a/lib/galaxy/webapps/galaxy/services/invocations.py +++ b/lib/galaxy/webapps/galaxy/services/invocations.py @@ -261,9 +261,7 @@ def create_from_store( payload: CreateInvocationFromStore, serialization_params: InvocationSerializationParams, ): - history = self._histories_manager.get_owned( - self.decode_id(payload.history_id), trans.user, current_history=trans.history - ) + history = self._histories_manager.get_owned(payload.history_id, trans.user, current_history=trans.history) object_tracker = self.create_objects_from_store( trans, payload, From bd42cd0db34a8acccd8ac37d0c7b587cd4138f23 Mon Sep 17 00:00:00 2001 From: Tillman Date: Fri, 12 Jan 2024 18:45:40 +0100 Subject: [PATCH 26/34] Fix typing --- lib/galaxy/schema/invocation.py | 43 ++++++++----- lib/galaxy/schema/schema.py | 12 ++-- lib/galaxy/webapps/galaxy/api/common.py | 2 +- .../webapps/galaxy/api/configuration.py | 3 +- lib/galaxy/webapps/galaxy/api/workflows.py | 61 +++++++++---------- 5 files changed, 64 insertions(+), 57 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index 55c083edcbd6..c68556242135 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -343,21 +343,34 @@ class InvocationStep(Model, WithModelClass): model_class: INVOCATION_STEP_MODEL_CLASS = ModelClassField(INVOCATION_STEP_MODEL_CLASS) id: Annotated[EncodedDatabaseIdField, Field(..., title="Invocation Step ID")] update_time: Optional[datetime] = schema.UpdateTimeField - job_id: Optional[EncodedDatabaseIdField] = Field( - default=None, - title="Job ID", - description="The encoded ID of the job associated with this workflow invocation step.", - ) - workflow_step_id: EncodedDatabaseIdField = Field( - ..., - title="Workflow step ID", - description="The encoded ID of the workflow step associated with this workflow invocation step.", - ) - subworkflow_invocation_id: Optional[EncodedDatabaseIdField] = Field( - default=None, - title="Subworkflow invocation ID", - description="The encoded ID of the subworkflow invocation.", - ) + job_id: Optional[ + Annotated[ + EncodedDatabaseIdField, + Field( + default=None, + title="Job ID", + description="The encoded ID of the job associated with this workflow invocation step.", + ), + ] + ] + workflow_step_id: Annotated[ + EncodedDatabaseIdField, + Field( + ..., + title="Workflow step ID", + description="The encoded ID of the workflow step associated with this workflow invocation step.", + ), + ] + subworkflow_invocation_id: Optional[ + Annotated[ + EncodedDatabaseIdField, + Field( + default=None, + title="Subworkflow invocation ID", + description="The encoded ID of the subworkflow invocation.", + ), + ] + ] state: Optional[Union[InvocationStepState, JobState]] = Field( default=None, title="State of the invocation step", diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 7e59383d133a..876576ba6681 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -1429,18 +1429,14 @@ class InvocationSortByEnum(str, Enum): class InvocationIndexQueryPayload(Model): - workflow_id: Optional[DecodedDatabaseIdField] = Field( + workflow_id: Optional[int] = Field( None, title="Workflow ID", description="Return only invocations for this Workflow ID" ) - history_id: Optional[DecodedDatabaseIdField] = Field( + history_id: Optional[int] = Field( None, title="History ID", description="Return only invocations for this History ID" ) - job_id: Optional[DecodedDatabaseIdField] = Field( - None, title="Job ID", description="Return only invocations for this Job ID" - ) - user_id: Optional[DecodedDatabaseIdField] = Field( - None, title="User ID", description="Return invocations for this User ID" - ) + job_id: Optional[int] = Field(None, title="Job ID", description="Return only invocations for this Job ID") + user_id: Optional[int] = Field(None, title="User ID", description="Return invocations for this User ID") sort_by: Optional[InvocationSortByEnum] = Field( None, title="Sort By", description="Sort Workflow Invocations by this attribute" ) diff --git a/lib/galaxy/webapps/galaxy/api/common.py b/lib/galaxy/webapps/galaxy/api/common.py index 952d1bbf5975..f4f38ed0a20d 100644 --- a/lib/galaxy/webapps/galaxy/api/common.py +++ b/lib/galaxy/webapps/galaxy/api/common.py @@ -153,7 +153,7 @@ def parse_serialization_params( def query_serialization_params( - view: Annotated[Optional[str], SerializationViewQueryParam] = None, + view: SerializationViewQueryParam = None, keys: Optional[str] = SerializationKeysQueryParam, ) -> SerializationParams: return parse_serialization_params(view=view, keys=keys) diff --git a/lib/galaxy/webapps/galaxy/api/configuration.py b/lib/galaxy/webapps/galaxy/api/configuration.py index 7e6006b97bed..7450103197dc 100644 --- a/lib/galaxy/webapps/galaxy/api/configuration.py +++ b/lib/galaxy/webapps/galaxy/api/configuration.py @@ -11,7 +11,6 @@ ) from fastapi import Path -from typing_extensions import Annotated from galaxy.managers.configuration import ConfigurationManager from galaxy.managers.context import ProvidesUserContext @@ -61,7 +60,7 @@ def whoami(self, trans: ProvidesUserContext = DependsOnTrans) -> Optional[UserMo def index( self, trans: ProvidesUserContext = DependsOnTrans, - view: Annotated[Optional[str], SerializationViewQueryParam] = None, + view: SerializationViewQueryParam = None, keys: Optional[str] = SerializationKeysQueryParam, ) -> Dict[str, Any]: """ diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 5e969e0f19b2..3422bd3d5076 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -56,7 +56,6 @@ InvocationMessageResponseModel, InvocationReport, InvocationSerializationParams, - InvocationSerializationView, InvocationStep, InvocationStepJobsResponseCollectionJobsModel, InvocationStepJobsResponseJobModel, @@ -1122,8 +1121,8 @@ def undelete_workflow( ) def show_versions( self, + workflow_id: StoredWorkflowIDPathParam, trans: ProvidesUserContext = DependsOnTrans, - workflow_id: DecodedDatabaseIdField = StoredWorkflowIDPathParam, instance: Annotated[Optional[bool], InstanceQueryParam] = False, ): return self.service.get_versions(trans, workflow_id, instance) @@ -1278,7 +1277,7 @@ class FastAPIInvocations: ) def create_invocations_from_store( self, - payload: Annotated[CreateInvocationsFromStorePayload, CreateInvocationsFromStoreBody], + payload: CreateInvocationsFromStoreBody, trans: ProvidesHistoryContext = DependsOnTrans, ) -> List[WorkflowInvocationResponse]: """ @@ -1299,18 +1298,18 @@ def create_invocations_from_store( def index_invocations( self, response: Response, - workflow_id: Annotated[Optional[DecodedDatabaseIdField], WorkflowIdQueryParam] = None, - history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, - job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, - user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, - sort_by: Annotated[Optional[InvocationSortByEnum], InvocationsSortByQueryParam] = None, - sort_desc: Annotated[Optional[bool], InvocationsSortDescQueryParam] = False, - include_terminal: Annotated[Optional[bool], InvocationsIncludeTerminalQueryParam] = True, - limit: Annotated[Optional[int], InvocationsLimitQueryParam] = None, - offset: Annotated[Optional[int], InvocationsOffsetQueryParam] = None, - instance: Annotated[Optional[bool], InvocationsInstanceQueryParam] = False, - view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, - step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, + workflow_id: WorkflowIdQueryParam = None, + history_id: HistoryIdQueryParam = None, + job_id: JobIdQueryParam = None, + user_id: UserIdQueryParam = None, + sort_by: InvocationsSortByQueryParam = None, + sort_desc: InvocationsSortDescQueryParam = False, + include_terminal: InvocationsIncludeTerminalQueryParam = True, + limit: InvocationsLimitQueryParam = None, + offset: InvocationsOffsetQueryParam = None, + instance: InvocationsInstanceQueryParam = False, + view: SerializationViewQueryParam = None, + step_details: StepDetailQueryParam = False, trans: ProvidesUserContext = DependsOnTrans, ) -> List[WorkflowInvocationResponse]: """If workflow_id is supplied (either via URL or query parameter) it should be an @@ -1322,6 +1321,10 @@ def index_invocations( :raises: exceptions.MessageException, exceptions.ObjectNotFound """ invocation_payload = InvocationIndexPayload( + workflow_id=workflow_id, + history_id=history_id, + job_id=job_id, + user_id=user_id, sort_by=sort_by, sort_desc=sort_desc, include_terminal=include_terminal, @@ -1329,10 +1332,6 @@ def index_invocations( offset=offset, instance=instance, ) - invocation_payload.workflow_id = workflow_id - invocation_payload.history_id = history_id - invocation_payload.job_id = job_id - invocation_payload.user_id = user_id serialization_params = InvocationSerializationParams( view=view, step_details=step_details, @@ -1349,18 +1348,18 @@ def index_invocations( def index_workflow_invocations( self, response: Response, - workflow_id: Annotated[DecodedDatabaseIdField, StoredWorkflowIDPathParam], - history_id: Annotated[Optional[DecodedDatabaseIdField], HistoryIdQueryParam] = None, - job_id: Annotated[Optional[DecodedDatabaseIdField], JobIdQueryParam] = None, - user_id: Annotated[Optional[DecodedDatabaseIdField], UserIdQueryParam] = None, - sort_by: Annotated[Optional[InvocationSortByEnum], InvocationsSortByQueryParam] = None, - sort_desc: Annotated[Optional[bool], InvocationsSortDescQueryParam] = False, - include_terminal: Annotated[Optional[bool], InvocationsIncludeTerminalQueryParam] = True, - limit: Annotated[Optional[int], InvocationsLimitQueryParam] = None, - offset: Annotated[Optional[int], InvocationsOffsetQueryParam] = None, - instance: Annotated[Optional[bool], InvocationsInstanceQueryParam] = False, - view: Annotated[Optional[InvocationSerializationView], SerializationViewQueryParam] = None, - step_details: Annotated[Optional[bool], StepDetailQueryParam] = False, + workflow_id: StoredWorkflowIDPathParam, + history_id: HistoryIdQueryParam = None, + job_id: JobIdQueryParam = None, + user_id: UserIdQueryParam = None, + sort_by: InvocationsSortByQueryParam = None, + sort_desc: InvocationsSortDescQueryParam = False, + include_terminal: InvocationsIncludeTerminalQueryParam = True, + limit: InvocationsLimitQueryParam = None, + offset: InvocationsOffsetQueryParam = None, + instance: InvocationsInstanceQueryParam = False, + view: SerializationViewQueryParam = None, + step_details: StepDetailQueryParam = False, trans: ProvidesUserContext = DependsOnTrans, ) -> List[WorkflowInvocationResponse]: """An alias for GET '/api/invocations'""" From 1f561c31c5497efc33dde7293bc4f4c242aec29d Mon Sep 17 00:00:00 2001 From: Tillman Date: Fri, 12 Jan 2024 18:49:22 +0100 Subject: [PATCH 27/34] Fix typing --- lib/galaxy/webapps/galaxy/api/workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 3422bd3d5076..86d5c02478b9 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -1123,7 +1123,7 @@ def show_versions( self, workflow_id: StoredWorkflowIDPathParam, trans: ProvidesUserContext = DependsOnTrans, - instance: Annotated[Optional[bool], InstanceQueryParam] = False, + instance: InstanceQueryParam = False, ): return self.service.get_versions(trans, workflow_id, instance) From ff8b7cd8cf897ae3556328d1f6aeb467eaa4ca89 Mon Sep 17 00:00:00 2001 From: Tillman Date: Fri, 12 Jan 2024 18:50:25 +0100 Subject: [PATCH 28/34] Regenerate the client schema --- client/src/api/schema/schema.ts | 90 ++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 5bb7821969cd..5e64efb5375b 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -3051,10 +3051,7 @@ export interface components { }; /** CreateInvocationsFromStorePayload */ CreateInvocationsFromStorePayload: { - /** - * History ID - * @example 0123456789ABCDEF - */ + /** History ID */ history_id: string; /** * Legacy Job State @@ -7134,11 +7131,8 @@ export interface components { * @example 0123456789ABCDEF */ id: string; - /** - * Job ID - * @description The encoded ID of the job associated with this workflow invocation step. - */ - job_id?: string | null; + /** Job Id */ + job_id: string | null; /** * Jobs * @description Jobs associated with the workflow invocation step. @@ -7177,11 +7171,8 @@ export interface components { * @description Describes where in the scheduling process the workflow invocation step is. */ state?: components["schemas"]["InvocationStepState"] | components["schemas"]["JobState"] | null; - /** - * Subworkflow invocation ID - * @description The encoded ID of the subworkflow invocation. - */ - subworkflow_invocation_id?: string | null; + /** Subworkflow Invocation Id */ + subworkflow_invocation_id: string | null; /** * Update Time * @description The last time and date this item was updated. @@ -11402,6 +11393,7 @@ export interface operations { * configuration settings are returned. */ parameters?: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -11823,6 +11815,7 @@ export interface operations { /** Search datasets or collections using a query system. */ parameters?: { /** @description Optional identifier of a History. Use it to restrict the search within a particular History. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -11908,6 +11901,7 @@ export interface operations { parameters: { /** @description The type of information about the dataset to be requested. */ /** @description The type of information about the dataset to be requested. Each of these values may require additional parameters in the request and may return different responses. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { hda_ldda?: components["schemas"]["DatasetSourceType"]; @@ -12007,6 +12001,7 @@ export interface operations { * **Note**: `view` and `keys` are also available to control the serialization of the dataset. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -13812,6 +13807,7 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { all?: boolean | null; @@ -13854,6 +13850,7 @@ export interface operations { * @description The new history can also be copied form a existing history or imported from an archive or URL. */ parameters?: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -13896,6 +13893,7 @@ export interface operations { * Archived histories are histories are not part of the active histories of the user but they can be accessed using this endpoint. */ parameters?: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -13967,6 +13965,7 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { all?: boolean | null; @@ -14005,6 +14004,7 @@ export interface operations { undelete_api_histories_deleted__history_id__undelete_post: { /** Restores a deleted history with the given ID (that hasn't been purged). */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14040,6 +14040,7 @@ export interface operations { create_from_store_api_histories_from_store_post: { /** Create histories from a model store. */ parameters?: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14104,6 +14105,7 @@ export interface operations { show_recent_api_histories_most_recently_used_get: { /** Returns the most recently used history of the user. */ parameters?: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14140,6 +14142,7 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { q?: string[] | null; @@ -14252,6 +14255,7 @@ export interface operations { /** @description Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item */ /** @description The maximum number of items to return. */ /** @description String containing one of the valid ordering attributes followed (optionally) by '-asc' or '-dsc' for ascending and descending order respectively. Orders can be stacked as a comma-separated list of values. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { q?: string[] | null; @@ -14289,6 +14293,7 @@ export interface operations { history_api_histories__history_id__get: { /** Returns the history with the given ID. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14324,6 +14329,7 @@ export interface operations { update_api_histories__history_id__put: { /** Updates the values for the history with the given ID. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14364,6 +14370,7 @@ export interface operations { delete_api_histories__history_id__delete: { /** Marks the history with the given ID as deleted. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { purge?: boolean; @@ -14556,6 +14563,7 @@ export interface operations { * @description Whether to return visible or hidden datasets only. Leave unset for both. */ /** @description Whether to return only shareable or not shareable datasets. Leave unset for both. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -14612,6 +14620,7 @@ export interface operations { * will be made to the items. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -14654,6 +14663,7 @@ export interface operations { */ parameters: { /** @description The type of the target history element. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"] | null; @@ -15244,6 +15254,7 @@ export interface operations { parameters: { /** @description The type of the target history element. */ /** @description This value can be used to broadly restrict the magnitude of the number of elements returned via the API for large collections. The number of actual elements returned may be "a bit" more than this number or "a lot" less - varying on the depth of nesting, balance of nesting at each level, and size of target collection. The consumer of this API should not expect a stable number or pre-calculable number of elements to be produced given this parameter - the only promise is that this API will not respond with an order of magnitude more elements estimated with this value. The UI uses this parameter to fetch a "balanced" concept of the "start" of large collections at every depth of the collection. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"]; @@ -15290,6 +15301,7 @@ export interface operations { */ parameters: { /** @description The type of the target history element. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"]; @@ -15353,6 +15365,7 @@ export interface operations { * @deprecated * @description Whether to stop the creating job if all outputs of the job have been deleted. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { type?: components["schemas"]["HistoryContentType"]; @@ -15464,6 +15477,7 @@ export interface operations { * @description Whether to return visible or hidden datasets only. Leave unset for both. */ /** @description Whether to return only shareable or not shareable datasets. Leave unset for both. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ /** @description Generally a property name to filter by followed by an (often optional) hyphen and operator string. */ /** @description The value to filter by. */ @@ -15520,6 +15534,7 @@ export interface operations { * @description Create a new `HDA` or `HDCA` in the given History. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -15577,6 +15592,7 @@ export interface operations { */ parameters: { /** @description This value can be used to broadly restrict the magnitude of the number of elements returned via the API for large collections. The number of actual elements returned may be "a bit" more than this number or "a lot" less - varying on the depth of nesting, balance of nesting at each level, and size of target collection. The consumer of this API should not expect a stable number or pre-calculable number of elements to be produced given this parameter - the only promise is that this API will not respond with an order of magnitude more elements estimated with this value. The UI uses this parameter to fetch a "balanced" concept of the "start" of large collections at every depth of the collection. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { fuzzy_count?: number | null; @@ -15622,6 +15638,7 @@ export interface operations { * @description Updates the values for the history content item with the given ``ID``. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -15685,6 +15702,7 @@ export interface operations { * @deprecated * @description Whether to stop the creating job if all outputs of the job have been deleted. */ + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { purge?: boolean | null; @@ -15855,6 +15873,7 @@ export interface operations { * or hand-crafted JSON dictionary. */ parameters: { + /** @description View to be passed to the serializer */ /** @description Comma-separated list of keys to be passed to the serializer */ query?: { view?: string | null; @@ -16559,19 +16578,31 @@ export interface operations { * :raises: exceptions.MessageException, exceptions.ObjectNotFound */ parameters?: { + /** @description Return only invocations for this Workflow ID */ + /** @description Return only invocations for this History ID */ + /** @description Return only invocations for this Job ID */ + /** @description Return invocations for this User ID. */ + /** @description Sort Workflow Invocations by this attribute */ + /** @description Sort in descending order? */ + /** @description Set to false to only include terminal Invocations. */ + /** @description Limit the number of invocations to return. */ + /** @description Number of invocations to skip. */ + /** @description Is provided workflow id for Workflow instead of StoredWorkflow? */ + /** @description View to be passed to the serializer */ + /** @description Include details for individual invocation steps and populate a steps attribute in the resulting dictionary. */ query?: { workflow_id?: string | null; history_id?: string | null; job_id?: string | null; user_id?: string | null; sort_by?: components["schemas"]["InvocationSortByEnum"] | null; - sort_desc?: boolean | null; + sort_desc?: boolean; include_terminal?: boolean | null; limit?: number | null; offset?: number | null; instance?: boolean | null; - view?: components["schemas"]["InvocationSerializationView"] | null; - step_details?: boolean | null; + view?: string | null; + step_details?: boolean; }; /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ header?: { @@ -16582,7 +16613,7 @@ export interface operations { /** @description Successful Response */ 200: { content: { - "application/json": components["schemas"]["WorkflowInvocationCollectionView"][]; + "application/json": components["schemas"]["WorkflowInvocationResponse"][]; }; }; /** @description Validation Error */ @@ -16613,7 +16644,7 @@ export interface operations { /** @description Successful Response */ 200: { content: { - "application/json": components["schemas"]["WorkflowInvocationCollectionView"][]; + "application/json": components["schemas"]["WorkflowInvocationResponse"][]; }; }; /** @description Validation Error */ @@ -21459,23 +21490,35 @@ export interface operations { * @description An alias for GET '/api/invocations' */ parameters: { + /** @description Return only invocations for this History ID */ + /** @description Return only invocations for this Job ID */ + /** @description Return invocations for this User ID. */ + /** @description Sort Workflow Invocations by this attribute */ + /** @description Sort in descending order? */ + /** @description Set to false to only include terminal Invocations. */ + /** @description Limit the number of invocations to return. */ + /** @description Number of invocations to skip. */ + /** @description Is provided workflow id for Workflow instead of StoredWorkflow? */ + /** @description View to be passed to the serializer */ + /** @description Include details for individual invocation steps and populate a steps attribute in the resulting dictionary. */ query?: { history_id?: string | null; job_id?: string | null; user_id?: string | null; sort_by?: components["schemas"]["InvocationSortByEnum"] | null; - sort_desc?: boolean | null; + sort_desc?: boolean; include_terminal?: boolean | null; limit?: number | null; offset?: number | null; instance?: boolean | null; - view?: components["schemas"]["InvocationSerializationView"] | null; - step_details?: boolean | null; + view?: string | null; + step_details?: boolean; }; /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ header?: { "run-as"?: string | null; }; + /** @description The encoded database identifier of the Stored Workflow. */ path: { workflow_id: string; }; @@ -21484,7 +21527,7 @@ export interface operations { /** @description Successful Response */ 200: { content: { - "application/json": components["schemas"]["WorkflowInvocationCollectionView"][]; + "application/json": components["schemas"]["WorkflowInvocationResponse"][]; }; }; /** @description Validation Error */ @@ -22414,6 +22457,7 @@ export interface operations { header?: { "run-as"?: string | null; }; + /** @description The encoded database identifier of the Stored Workflow. */ path: { workflow_id: string; }; From b6186cc28444fb65434006680455791b58a47554 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sun, 14 Jan 2024 12:49:25 +0100 Subject: [PATCH 29/34] Refine pydantic models --- lib/galaxy/schema/invocation.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py index c68556242135..df81f450de32 100644 --- a/lib/galaxy/schema/invocation.py +++ b/lib/galaxy/schema/invocation.py @@ -489,11 +489,6 @@ class InvocationUpdatePayload(Model): class InvocationIOBase(Model): - # TODO - resolve - # the tests in test/integration/test_workflow_tasks.py , - # between line 42 and 56 fail, if this id is not allowed be None - # They all fail, when trying to populate the response of the show_invocation operation - # Is it intended to allow None here? id: Optional[EncodedDatabaseIdField] = Field( default=None, title="ID", description="The encoded ID of the dataset/dataset collection." ) @@ -621,9 +616,9 @@ class InvocationStepJobsResponseCollectionJobsModel(InvocationJobsSummaryBaseMod class CreateInvocationFromStore(StoreContentSource): - # TODO - add proper description - history_id: DecodedDatabaseIdField = Field(default=..., title="History ID", description="") - model_config = ConfigDict(extra="allow") + history_id: int = Field( + default=..., title="History ID", description="The ID of the history associated with the invocations." + ) class InvocationSerializationView(str, Enum): @@ -660,5 +655,8 @@ class InvocationSerializationParams(BaseModel): class CreateInvocationsFromStorePayload(CreateInvocationFromStore, InvocationSerializationParams): - # TODO - add proper description - history_id: str = Field(default=..., title="History ID", description="") + history_id: DecodedDatabaseIdField = Field( + default=..., + title="History ID", + description="The ID of the history associated with the invocations.", + ) From d9b663d2f0b36732f1f24a66809f28f5457b5612 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sun, 14 Jan 2024 12:49:44 +0100 Subject: [PATCH 30/34] Remove comments --- lib/galaxy/webapps/galaxy/api/workflows.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 86d5c02478b9..58ef01a77c56 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -1281,7 +1281,6 @@ def create_invocations_from_store( trans: ProvidesHistoryContext = DependsOnTrans, ) -> List[WorkflowInvocationResponse]: """ - TODO - expose anonymous Input can be an archive describing a Galaxy model store containing an workflow invocation - for instance one created with with write_store or prepare_store_download endpoint. @@ -1318,7 +1317,6 @@ def index_invocations( query. If neither a workflow_id or history_id is supplied, all the current user's workflow invocations will be indexed (as determined by the invocation being executed on one of the user's histories) - :raises: exceptions.MessageException, exceptions.ObjectNotFound """ invocation_payload = InvocationIndexPayload( workflow_id=workflow_id, @@ -1720,7 +1718,6 @@ def workflow_invocation_jobs_summary( """An alias for `GET /api/invocations/{invocation_id}/jobs_summary`. `workflow_id` is ignored.""" return self.invocation_jobs_summary(trans=trans, invocation_id=invocation_id) - # Should I even create models for those as they will be removed? # TODO: remove this endpoint after 23.1 release @router.get( "/api/invocations/{invocation_id}/biocompute", From 2bfca310b237ca6633aa99f9b780c3c3864d4ed2 Mon Sep 17 00:00:00 2001 From: Tillman Date: Sun, 14 Jan 2024 12:52:14 +0100 Subject: [PATCH 31/34] Regenerate the client schema --- client/src/api/schema/schema.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 5e64efb5375b..883068aee32a 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -917,7 +917,6 @@ export interface paths { * query. If neither a workflow_id or history_id is supplied, all the current user's * workflow invocations will be indexed (as determined by the invocation being * executed on one of the user's histories) - * :raises: exceptions.MessageException, exceptions.ObjectNotFound */ get: operations["index_invocations_api_invocations_get"]; }; @@ -3051,7 +3050,11 @@ export interface components { }; /** CreateInvocationsFromStorePayload */ CreateInvocationsFromStorePayload: { - /** History ID */ + /** + * History ID + * @description The ID of the history associated with the invocations. + * @example 0123456789ABCDEF + */ history_id: string; /** * Legacy Job State @@ -3079,7 +3082,6 @@ export interface components { * @description The name of the view used to serialize this item. This will return a predefined set of attributes of the item. */ view?: components["schemas"]["InvocationSerializationView"] | null; - [key: string]: unknown | undefined; }; /** CreateLibrariesFromStore */ CreateLibrariesFromStore: { @@ -16575,7 +16577,6 @@ export interface operations { * query. If neither a workflow_id or history_id is supplied, all the current user's * workflow invocations will be indexed (as determined by the invocation being * executed on one of the user's histories) - * :raises: exceptions.MessageException, exceptions.ObjectNotFound */ parameters?: { /** @description Return only invocations for this Workflow ID */ From d1487e98b7efd462b9b51133e6219f563d356d70 Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 16 Jan 2024 12:50:04 +0100 Subject: [PATCH 32/34] Include deprecated route in tests --- lib/galaxy_test/api/test_workflows.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/galaxy_test/api/test_workflows.py b/lib/galaxy_test/api/test_workflows.py index 68386bfe4792..aa0d83b3c9e5 100644 --- a/lib/galaxy_test/api/test_workflows.py +++ b/lib/galaxy_test/api/test_workflows.py @@ -7102,9 +7102,9 @@ def test_invocations_accessible_imported_workflow(self): self._assert_status_code_is(other_import_response, 200) other_id = other_import_response.json()["id"] workflow_request, history_id, _ = self._setup_workflow_run(workflow_id=other_id) - # response = self._get(f"workflows/{other_id}/usage") - # self._assert_status_code_is(response, 200) - # assert len(response.json()) == 0 + response = self._get(f"workflows/{other_id}/usage") + self._assert_status_code_is(response, 200) + assert len(response.json()) == 0 run_workflow_response = self.workflow_populator.invoke_workflow_raw( workflow_id, workflow_request, assert_ok=True ) @@ -7118,9 +7118,9 @@ def test_invocations_accessible_published_workflow(self): workflow_id = self.workflow_populator.simple_workflow("test_usage", publish=True) with self._different_user(): workflow_request, history_id, _ = self._setup_workflow_run(workflow_id=workflow_id) - # response = self._get(f"workflows/{workflow_id}/usage") - # self._assert_status_code_is(response, 200) - # assert len(response.json()) == 0 + response = self._get(f"workflows/{workflow_id}/usage") + self._assert_status_code_is(response, 200) + assert len(response.json()) == 0 run_workflow_response = self.workflow_populator.invoke_workflow_raw( workflow_id, workflow_request, assert_ok=True ) @@ -7133,9 +7133,9 @@ def test_invocations_accessible_published_workflow(self): def test_invocations_not_accessible_by_different_user_for_published_workflow(self): workflow_id = self.workflow_populator.simple_workflow("test_usage", publish=True) workflow_request, history_id, _ = self._setup_workflow_run(workflow_id=workflow_id) - # response = self._get(f"workflows/{workflow_id}/usage") - # self._assert_status_code_is(response, 200) - # assert len(response.json()) == 0 + response = self._get(f"workflows/{workflow_id}/usage") + self._assert_status_code_is(response, 200) + assert len(response.json()) == 0 run_workflow_response = self.workflow_populator.invoke_workflow_raw( workflow_id, workflow_request, assert_ok=True ) From fa69fd150c45d74c15f0a62183956486aa465751 Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 16 Jan 2024 12:51:55 +0100 Subject: [PATCH 33/34] Add deprecated path to index_workflow_invocations operation --- lib/galaxy/webapps/galaxy/api/workflows.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 58ef01a77c56..10e130a8781f 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -1311,13 +1311,6 @@ def index_invocations( step_details: StepDetailQueryParam = False, trans: ProvidesUserContext = DependsOnTrans, ) -> List[WorkflowInvocationResponse]: - """If workflow_id is supplied (either via URL or query parameter) it should be an - encoded StoredWorkflow id and returned invocations will be restricted to that - workflow. history_id (an encoded History id) can be used to further restrict the - query. If neither a workflow_id or history_id is supplied, all the current user's - workflow invocations will be indexed (as determined by the invocation being - executed on one of the user's histories) - """ invocation_payload = InvocationIndexPayload( workflow_id=workflow_id, history_id=history_id, @@ -1343,6 +1336,12 @@ def index_invocations( summary="Get the list of a user's workflow invocations.", name="index_invocations", ) + @router.get( + "/api/workflows/{workflow_id}/usage", + summary="Get the list of a user's workflow invocations.", + name="index_invocations", + deprecated=True, + ) def index_workflow_invocations( self, response: Response, @@ -1360,7 +1359,6 @@ def index_workflow_invocations( step_details: StepDetailQueryParam = False, trans: ProvidesUserContext = DependsOnTrans, ) -> List[WorkflowInvocationResponse]: - """An alias for GET '/api/invocations'""" invocations = self.index_invocations( response=response, workflow_id=workflow_id, From 03a04c01cf383b9050cf9fd42feba9aa6f52d33f Mon Sep 17 00:00:00 2001 From: Tillman Date: Tue, 16 Jan 2024 12:53:18 +0100 Subject: [PATCH 34/34] Regnerate client schema --- client/src/api/schema/schema.ts | 91 +++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 883068aee32a..3d737e261904 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -909,15 +909,7 @@ export interface paths { post: operations["write_store_api_histories__history_id__write_store_post"]; }; "/api/invocations": { - /** - * Get the list of a user's workflow invocations. - * @description If workflow_id is supplied (either via URL or query parameter) it should be an - * encoded StoredWorkflow id and returned invocations will be restricted to that - * workflow. history_id (an encoded History id) can be used to further restrict the - * query. If neither a workflow_id or history_id is supplied, all the current user's - * workflow invocations will be indexed (as determined by the invocation being - * executed on one of the user's histories) - */ + /** Get the list of a user's workflow invocations. */ get: operations["index_invocations_api_invocations_get"]; }; "/api/invocations/from_store": { @@ -1808,10 +1800,7 @@ export interface paths { put: operations["enable_link_access_api_workflows__workflow_id__enable_link_access_put"]; }; "/api/workflows/{workflow_id}/invocations": { - /** - * Get the list of a user's workflow invocations. - * @description An alias for GET '/api/invocations' - */ + /** Get the list of a user's workflow invocations. */ get: operations["index_invocations_api_workflows__workflow_id__invocations_get"]; }; "/api/workflows/{workflow_id}/invocations/{invocation_id}": { @@ -1919,6 +1908,13 @@ export interface paths { */ put: operations["unpublish_api_workflows__workflow_id__unpublish_put"]; }; + "/api/workflows/{workflow_id}/usage": { + /** + * Get the list of a user's workflow invocations. + * @deprecated + */ + get: operations["index_invocations_api_workflows__workflow_id__usage_get"]; + }; "/api/workflows/{workflow_id}/usage/{invocation_id}": { /** * Get detailed description of a workflow invocation. @@ -16569,15 +16565,7 @@ export interface operations { }; }; index_invocations_api_invocations_get: { - /** - * Get the list of a user's workflow invocations. - * @description If workflow_id is supplied (either via URL or query parameter) it should be an - * encoded StoredWorkflow id and returned invocations will be restricted to that - * workflow. history_id (an encoded History id) can be used to further restrict the - * query. If neither a workflow_id or history_id is supplied, all the current user's - * workflow invocations will be indexed (as determined by the invocation being - * executed on one of the user's histories) - */ + /** Get the list of a user's workflow invocations. */ parameters?: { /** @description Return only invocations for this Workflow ID */ /** @description Return only invocations for this History ID */ @@ -21486,10 +21474,7 @@ export interface operations { }; }; index_invocations_api_workflows__workflow_id__invocations_get: { - /** - * Get the list of a user's workflow invocations. - * @description An alias for GET '/api/invocations' - */ + /** Get the list of a user's workflow invocations. */ parameters: { /** @description Return only invocations for this History ID */ /** @description Return only invocations for this Job ID */ @@ -22153,6 +22138,60 @@ export interface operations { }; }; }; + index_invocations_api_workflows__workflow_id__usage_get: { + /** + * Get the list of a user's workflow invocations. + * @deprecated + */ + parameters: { + /** @description Return only invocations for this History ID */ + /** @description Return only invocations for this Job ID */ + /** @description Return invocations for this User ID. */ + /** @description Sort Workflow Invocations by this attribute */ + /** @description Sort in descending order? */ + /** @description Set to false to only include terminal Invocations. */ + /** @description Limit the number of invocations to return. */ + /** @description Number of invocations to skip. */ + /** @description Is provided workflow id for Workflow instead of StoredWorkflow? */ + /** @description View to be passed to the serializer */ + /** @description Include details for individual invocation steps and populate a steps attribute in the resulting dictionary. */ + query?: { + history_id?: string | null; + job_id?: string | null; + user_id?: string | null; + sort_by?: components["schemas"]["InvocationSortByEnum"] | null; + sort_desc?: boolean; + include_terminal?: boolean | null; + limit?: number | null; + offset?: number | null; + instance?: boolean | null; + view?: string | null; + step_details?: boolean; + }; + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + header?: { + "run-as"?: string | null; + }; + /** @description The encoded database identifier of the Stored Workflow. */ + path: { + workflow_id: string; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["WorkflowInvocationResponse"][]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; show_workflow_invocation_api_workflows__workflow_id__usage__invocation_id__get: { /** * Get detailed description of a workflow invocation.