Feature suggestion: "Re-Run" button
Hello, this is a feature that some of my users requested: the ability to easily re-run a job (or at least see the parameters that were used to create a specific dataset). This patch adds a 're-run' link (next to the 'save' link). The link is encoded in a way to trick the 'tool_runner' controller into displaying the tool-form with the parameters already initialized. The encoded URL looks like: http://localhost:8080/tool_runner?tool_id=addValue&dbkey=%3F&exp=143&input=2&iterate=yes&tool_state=800255ad656562346437643063633235303139616632363666336663343331613564633066343236353634373a37623232356635663730363136373635356635663232336132303330326332303232363936653730373537343232336132303232333332323263323032323635373837303232336132303232356332323331356332323232326332303232363937343635373236313734363532323361323032323563323236653666356332323232376471002e&chromInfo=%2Fhome%2Fgordon%2Ftemp%2Fgalaxy7%2Ftool-data%2Fshared%2Fucsc%2Fchrom%2F%3F.len This is just a proof of concept, and there are many problems with it (one is that conditionals/grouping don't work) and many possible improvements. The code itself is a hodge-podge of lines copied from different classes... (not be best example of python code). I'm sure there's a better why to do it, because constructing a workflow from a history is basically the same thing, but I don't understand the galaxy code good enough for that. Comments are welcomed, -gordon.
Assaf, This is great, but passing the tool state along the URL may be problematic for more complex tools. An alternative way with only very small changes from your code would be to add a "rerun" method to the tool_runner controller taking a dataset_id as an attribute. This would then do exactly what you've done below -- reconstitute a tool_state from the dataset_id, and then call the index method with the right arguments (rather than encoding on the url). I can do this and integrate your change, but I thought you might want to take a stab at it? Thanks, James On Jul 24, 2009, at 1:13 AM, Assaf Gordon wrote:
Hello,
this is a feature that some of my users requested: the ability to easily re-run a job (or at least see the parameters that were used to create a specific dataset).
This patch adds a 're-run' link (next to the 'save' link). The link is encoded in a way to trick the 'tool_runner' controller into displaying the tool-form with the parameters already initialized.
This is just a proof of concept, and there are many problems with it (one is that conditionals/grouping don't work) and many possible improvements. The code itself is a hodge-podge of lines copied from different classes... (not be best example of python code).
I'm sure there's a better why to do it, because constructing a workflow from a history is basically the same thing, but I don't understand the galaxy code good enough for that.
Comments are welcomed, -gordon. <galaxy_rerun_button.png>diff -r 8825d62bb2a4 lib/galaxy/model/ __init__.py --- a/lib/galaxy/model/__init__.py Thu Jul 23 22:59:26 2009 -0400 +++ b/lib/galaxy/model/__init__.py Fri Jul 24 00:47:35 2009 -0400 @@ -15,6 +15,7 @@ import galaxy.datatypes.registry from galaxy.datatypes.metadata import MetadataCollection from galaxy.security import RBACAgent, get_permitted_actions +from galaxy.web.framework import url_for
import logging log = logging.getLogger( __name__ ) @@ -571,6 +571,70 @@ return self.datatype.display_name( self ) def display_info( self ): return self.datatype.display_info( self ) + def get_rerun_tool_url ( self, trans ): + """ + Returns a URL which will run the tool that created this dataset, + with the same parameters. + + On failure, returns an empty string. + + Doesn't throw exceptions, because it is called from within a mako template + (an exception will stop the HTML generation) + """ + # will 'data' be the same as 'self'? + data = trans.app.model.HistoryDatasetAssociation.get( self.id ) + + # Get the associated job, if any (copied from ./lib/galaxy/ web/controller/workflow.py, line 754) + #if this hda was copied from another, we need to find the job that created the origial hda + job_hda = data + while job_hda.copied_from_history_dataset_association: + job_hda = job_hda.copied_from_history_dataset_association + if not job_hda.creating_job_associations: + #raise Exception ( "Could not find the job for this dataset." ) + return "" + + # Get the job object + job = None + for assoc in job_hda.creating_job_associations: + job = assoc.job ; + break + if not job: + #raise Exception("Failed to get assoc.job for dataset hid %d" % id) + return "" + + try: + tool = trans.app.toolbox.tools_by_id[ job.tool_id ] + except: + #raise Exception("Tool not found (%s), is it too old/ obsolete?" % ( job.tool_id)) + return "" + + # create an tool_state string, to fool 'tool_runner' into thinking it's an existing tool configuration + # (without a tool_state, 'tool_runner' creates a new state, and ignores the incoming parameters, see 'handle_input()') + state = tool.new_state( trans ) + tool_state_string = util.object_to_string(state.encode(tool, trans.app)) + + # Get the parameters, convert them into a dictionary + try: + param_values = job.get_param_values ( trans.app ) + except: + #raise Exception("Failed to get params for data id %d " % id) + return "" + + # Create a dictionary of string parameters + # Datasets are converted from the object to the id + tool_params = { } + for name, value in param_values.items(): + if isinstance(value, trans.app.model.HistoryDatasetAssociation ): + value = value.id + tool_params [ str(name) ] = str(value) + + url = galaxy.web.framework.url_for ( controller="tool_runner", + tool_id=job.tool_id, + tool_state=tool_state_string, + **tool_params ) + html_code = "<a href=\"%s\" target=\"galaxy_main\">Re-run</ a>" % url + return html_code + def get_converted_files_by_type( self, file_type ): valid = [] for assoc in self.implicitly_converted_datasets: diff -r 8825d62bb2a4 templates/root/history_common.mako --- a/templates/root/history_common.mako Thu Jul 23 22:59:26 2009 -0400 +++ b/templates/root/history_common.mako Fri Jul 24 00:47:35 2009 -0400 @@ -83,5 +83,6 @@ %if data.has_data: <a href="${h.url_for( action='display', id=data.id, tofile='yes', toext=data.ext )}" target="_blank">save</a> + ${data.get_rerun_tool_url(trans)} %for display_app in data.datatype.get_display_types(): <% display_links = data.datatype.get_display_links( data, display_app, app, request.base ) %> %if len( display_links ) > 0: _______________________________________________ galaxy-dev mailing list galaxy-dev@bx.psu.edu http://mail.bx.psu.edu/cgi-bin/mailman/listinfo/galaxy-dev
-- jt James Taylor Assistant Professor Department of Biology Department of Mathematics & Computer Science Emory University
James Taylor wrote, On 07/24/2009 11:58 AM:
On Jul 24, 2009, at 1:13 AM, Assaf Gordon wrote:
This patch adds a 're-run' link (next to the 'save' link). The link is encoded in a way to trick the 'tool_runner' controller into displaying the tool-form with the parameters already initialized.
An alternative way with only very small changes from your code would be to add a "rerun" method to the tool_runner controller taking a dataset_id as an attribute.
New patch, does exactly as you suggested. Indeed, a much cleaner solution. conditional,grouping and repeat parameters still don't work, because I convert all the parameters into strings. Without converting into strings, dynamic selection parameters are 'parameters.basic.UnvalidatedValue' objects and cause an exception. This is obviously wrong, but I don't know what's the correct way. I've also added a 're-run' link to failed jobs, so they can be re-run easily. Comments are welcomed. gordon.
I think the trick here is that you can actually skip the call do handle_input, you already have a ready to go tool state with the right stuff in it. Just need to figure out what needs to be in "vars" so the template renders correctly. And the answer to that question is probably dict( tool_state=tool_state, errors = {} ) On Jul 24, 2009, at 6:34 PM, Assaf Gordon wrote:
conditional,grouping and repeat parameters still don't work, because I convert all the parameters into strings. Without converting into strings, dynamic selection parameters are 'parameters.basic.UnvalidatedValue' objects and cause an exception. This is obviously wrong, but I don't know what's the correct way.
-- jt James Taylor Assistant Professor Department of Biology Department of Mathematics & Computer Science Emory University
James, With you suggestions, this version works with repeats and conditionals. The only 'hack' is to convert UnvalidatedValues into strings. Thanks for your help! Comments are welcomed, gordon.
participants (2)
-
Assaf Gordon
-
James Taylor