diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 0c797db31fa..0226c5d97ac 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -82,11 +82,17 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesHis latest_workflow = stored_workflow.latest_workflow inputs = {} for step in latest_workflow.steps: - if step.type == 'data_input': + step_type = step.type + if step_type in ['data_input', 'data_collection_input']: if step.tool_inputs and "name" in step.tool_inputs: - inputs[step.id] = {'label': step.tool_inputs['name'], 'value': ""} + label = step.tool_inputs['name'] + elif step_type == "data_input": + label = "Input Dataset" + elif step_type == "data_collection_input": + label = "Input Dataset Collection" else: - inputs[step.id] = {'label': "Input Dataset", 'value': ""} + raise ValueError("Invalid step_type %s" % step_type) + inputs[step.id] = {'label': label, 'value': ""} else: pass # Eventually, allow regular tool parameters to be inserted and modified at runtime. @@ -258,26 +264,35 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesHis try: if inputs[k]['src'] == 'ldda': ldda = trans.sa_session.query(self.app.model.LibraryDatasetDatasetAssociation).get( - trans.security.decode_id(inputs[k]['id'])) + trans.security.decode_id(inputs[k]['id'])) assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ) - hda = ldda.to_history_dataset_association(history, add_to_history=add_to_history) + content = ldda.to_history_dataset_association(history, add_to_history=add_to_history) elif inputs[k]['src'] == 'ld': ldda = trans.sa_session.query(self.app.model.LibraryDataset).get( - trans.security.decode_id(inputs[k]['id'])).library_dataset_dataset_association + trans.security.decode_id(inputs[k]['id'])).library_dataset_dataset_association assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), ldda.dataset ) - hda = ldda.to_history_dataset_association(history, add_to_history=add_to_history) + content = ldda.to_history_dataset_association(history, add_to_history=add_to_history) elif inputs[k]['src'] == 'hda': # Get dataset handle, add to dict and history if necessary - hda = trans.sa_session.query(self.app.model.HistoryDatasetAssociation).get( - trans.security.decode_id(inputs[k]['id'])) - assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), hda.dataset ) + content = trans.sa_session.query(self.app.model.HistoryDatasetAssociation).get( + trans.security.decode_id(inputs[k]['id'])) + assert trans.user_is_admin() or trans.app.security_agent.can_access_dataset( trans.get_current_user_roles(), content.dataset ) + elif inputs[k]['src'] == 'hdca': + content = self.app.dataset_collections_service.get_dataset_collection_instance( + trans, + 'history', + inputs[k]['id'] + ) else: trans.response.status = 400 return "Unknown dataset source '%s' specified." % inputs[k]['src'] - if add_to_history and hda.history != history: - hda = hda.copy() - history.add_dataset(hda) - inputs[k]['hda'] = hda + if add_to_history and content.history != history: + content = content.copy() + if isinstance( content, self.app.model.HistoryDatasetAssociation ): + history.add_dataset( content ) + else: + history.add_dataset_collection( content ) + inputs[k]['hda'] = content # TODO: rename key to 'content', prescreen input ensure not populated explicitly except AssertionError: trans.response.status = 400 return "Invalid Dataset '%s' Specified" % inputs[k]['id'] diff --git a/lib/galaxy/workflow/run.py b/lib/galaxy/workflow/run.py index 28f24329d37..efe73265be6 100644 --- a/lib/galaxy/workflow/run.py +++ b/lib/galaxy/workflow/run.py @@ -290,7 +290,7 @@ class WorkflowInvoker( object ): step.state = step.module.get_runtime_state() # This is an input step. Make sure we have an available input. - if step.type == 'data_input': + if step.type in [ 'data_input', 'data_collection_input' ]: if self.inputs_by == "step_id": key = str( step.id ) elif self.inputs_by == "name": diff --git a/test/api/helpers.py b/test/api/helpers.py index 7aa550847ec..82eefbdb72e 100644 --- a/test/api/helpers.py +++ b/test/api/helpers.py @@ -11,6 +11,8 @@ workflow_str = resource_string( __name__, "test_workflow_1.ga" ) # Simple workflow that takes an input and filters with random lines twice in a # row - first grabbing 8 lines at random and then 6. workflow_random_x2_str = resource_string( __name__, "test_workflow_2.ga" ) +workflow_two_paired_str = resource_string( __name__, "test_workflow_two_paired.ga" ) + DEFAULT_HISTORY_TIMEOUT = 10 # Secs to wait on history to turn ok @@ -140,6 +142,9 @@ class WorkflowPopulator( object ): def load_random_x2_workflow( self, name ): return self.load_workflow( name, content=workflow_random_x2_str ) + def load_two_paired_workflow( self, name ): + return self.load_workflow( name, content=workflow_two_paired_str ) + def simple_workflow( self, name, **create_kwds ): workflow = self.load_workflow( name ) return self.create_workflow( workflow, **create_kwds ) diff --git a/test/api/test_workflow_two_paired.ga b/test/api/test_workflow_two_paired.ga new file mode 100644 index 00000000000..be7643ba326 --- /dev/null +++ b/test/api/test_workflow_two_paired.ga @@ -0,0 +1,116 @@ +{ + "a_galaxy_workflow": "true", + "annotation": "", + "format-version": "0.1", + "name": "MultipairTest223", + "steps": { + "0": { + "annotation": "", + "id": 0, + "input_connections": {}, + "inputs": [ + { + "description": "", + "name": "f1" + } + ], + "name": "Input dataset collection", + "outputs": [], + "position": { + "left": 302.3333435058594, + "top": 330 + }, + "tool_errors": null, + "tool_id": null, + "tool_state": "{\"collection_type\": \"paired\", \"name\": \"f1\"}", + "tool_version": null, + "type": "data_collection_input", + "user_outputs": [] + }, + "1": { + "annotation": "", + "id": 1, + "input_connections": {}, + "inputs": [ + { + "description": "", + "name": "f2" + } + ], + "name": "Input dataset collection", + "outputs": [], + "position": { + "left": 288.3333435058594, + "top": 446 + }, + "tool_errors": null, + "tool_id": null, + "tool_state": "{\"collection_type\": \"paired\", \"name\": \"f2\"}", + "tool_version": null, + "type": "data_collection_input", + "user_outputs": [] + }, + "2": { + "annotation": "", + "id": 2, + "input_connections": { + "kind|f1": { + "id": 0, + "output_name": "output" + }, + "kind|f2": { + "id": 1, + "output_name": "output" + } + }, + "inputs": [], + "name": "collection_two_paired", + "outputs": [ + { + "name": "out1", + "type": "txt" + } + ], + "position": { + "left": 782.3333740234375, + "top": 200 + }, + "post_job_actions": {}, + "tool_errors": null, + "tool_id": "collection_two_paired", + "tool_state": "{\"__page__\": 0, \"kind\": \"{\\\"f1\\\": null, \\\"f2\\\": null, \\\"collection_type\\\": \\\"paired\\\", \\\"__current_case__\\\": 0}\", \"__rerun_remap_job_id__\": null}", + "tool_version": "0.1.0", + "type": "tool", + "user_outputs": [] + }, + "3": { + "annotation": "", + "id": 3, + "input_connections": { + "cond1|input1": { + "id": 2, + "output_name": "out1" + } + }, + "inputs": [], + "name": "Concatenate datasets", + "outputs": [ + { + "name": "out_file1", + "type": "input" + } + ], + "position": { + "left": 1239.3333740234375, + "top": 108.97916793823242 + }, + "post_job_actions": {}, + "tool_errors": null, + "tool_id": "cat2", + "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"cond1\": \"{\\\"datatype\\\": \\\"txt\\\", \\\"input1\\\": null, \\\"__current_case__\\\": 0}\"}", + "tool_version": "1.0.0", + "type": "tool", + "user_outputs": [] + } + } +} \ No newline at end of file diff --git a/test/api/test_workflows.py b/test/api/test_workflows.py index 600828d0aa4..b2416bbcc66 100644 --- a/test/api/test_workflows.py +++ b/test/api/test_workflows.py @@ -85,6 +85,25 @@ class WorkflowsApiTestCase( api.ApiTestCase ): self._assert_status_code_is( run_workflow_response, 200 ) self.dataset_populator.wait_for_history( history_id, assert_ok=True ) + @skip_without_tool( "cat1" ) + @skip_without_tool( "collection_two_paired" ) + def test_run_workflow_collection_params( self ): + workflow = self.workflow_populator.load_two_paired_workflow( name="test_for_run_two_paired" ) + workflow_id = self.workflow_populator.create_workflow( workflow ) + history_id = self.dataset_populator.new_history() + hdca1 = self.dataset_collection_populator.create_pair_in_history( history_id, contents=["1 2 3", "4 5 6"] ).json() + hdca2 = self.dataset_collection_populator.create_pair_in_history( history_id, contents=["7 8 9", "0 a b"] ).json() + self.dataset_populator.wait_for_history( history_id, assert_ok=True ) + label_map = { "f1": self._ds_entry( hdca1 ), "f2": self._ds_entry( hdca2 ) } + workflow_request = dict( + history="hist_id=%s" % history_id, + workflow_id=workflow_id, + ds_map=self._build_ds_map( workflow_id, label_map ), + ) + run_workflow_response = self._post( "workflows", data=workflow_request ) + self._assert_status_code_is( run_workflow_response, 200 ) + self.dataset_populator.wait_for_history( history_id, assert_ok=True ) + @skip_without_tool( "cat1" ) def test_extract_from_history( self ): history_id = self.dataset_populator.new_history() @@ -137,7 +156,6 @@ class WorkflowsApiTestCase( api.ApiTestCase ): input1 = tool_step[ "input_connections" ][ "input1" ] input2 = tool_step[ "input_connections" ][ "queries_0|input2" ] - print downloaded_workflow self.assertEquals( input_steps[ 0 ][ "id" ], input1[ "id" ] ) self.assertEquals( input_steps[ 1 ][ "id" ], input2[ "id" ] ) @@ -421,21 +439,34 @@ class WorkflowsApiTestCase( api.ApiTestCase ): # renamed to 'the_new_name'. assert "the_new_name" in map( lambda hda: hda[ "name" ], contents ) - def _setup_workflow_run( self, workflow, history_id=None ): + def _setup_workflow_run( self, workflow, inputs_by='step_id', history_id=None ): uploaded_workflow_id = self.workflow_populator.create_workflow( workflow ) if not history_id: history_id = self.dataset_populator.new_history() hda1 = self.dataset_populator.new_dataset( history_id, content="1 2 3" ) hda2 = self.dataset_populator.new_dataset( history_id, content="4 5 6" ) + workflow_request = dict( + history="hist_id=%s" % history_id, + workflow_id=uploaded_workflow_id, + ) label_map = { 'WorkflowInput1': self._ds_entry(hda1), 'WorkflowInput2': self._ds_entry(hda2) } - workflow_request = dict( - history="hist_id=%s" % history_id, - workflow_id=uploaded_workflow_id, - ds_map=self._build_ds_map( uploaded_workflow_id, label_map ), - ) + if inputs_by == 'step_id': + ds_map = self._build_ds_map( uploaded_workflow_id, label_map ) + workflow_request[ "ds_map" ] = ds_map + elif inputs_by == "step_index": + index_map = { + '0': self._ds_entry(hda1), + '1': self._ds_entry(hda2) + } + workflow_request[ "inputs" ] = dumps( index_map ) + workflow_request[ "inputs_by" ] = 'step_index' + elif inputs_by == "name": + workflow_request[ "inputs" ] = dumps( label_map ) + workflow_request[ "inputs_by" ] = 'name' + return workflow_request, history_id def _build_ds_map( self, workflow_id, label_map ): @@ -471,7 +502,10 @@ class WorkflowsApiTestCase( api.ApiTestCase ): return workflow_inputs def _ds_entry( self, hda ): - return dict( src="hda", id=hda[ "id" ] ) + src = 'hda' + if 'history_content_type' in hda and hda[ 'history_content_type' ] == "dataset_collection": + src = 'hdca' + return dict( src=src, id=hda[ "id" ] ) def _assert_user_has_workflow_with_name( self, name ): names = self.__workflow_names() diff --git a/test/functional/tools/collection_two_paired.xml b/test/functional/tools/collection_two_paired.xml index df34b1eea92..af4c6072a5e 100644 --- a/test/functional/tools/collection_two_paired.xml +++ b/test/functional/tools/collection_two_paired.xml @@ -16,12 +16,12 @@ - - + + - - + +