Skip to content

Commit

Permalink
Add ability to import workflows without Galaxy modifying tool version.
Browse files Browse the repository at this point in the history
Needed to test workflow tool upgrades when loading workflows, but I think it is good to have a way to preserve the original tool state as well for the sake of absolute reproducibility/tracibility.
  • Loading branch information
jmchilton committed Jan 8, 2017
1 parent de35c85 commit a0177fe
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 16 deletions.
14 changes: 8 additions & 6 deletions lib/galaxy/managers/workflows.py
Expand Up @@ -190,6 +190,7 @@ def build_workflow_from_dict(
add_to_menu=False,
publish=False,
create_stored_workflow=True,
exact_tools=False,
):
# Put parameters in workflow mode
trans.workflow_building_mode = True
Expand All @@ -202,6 +203,7 @@ def build_workflow_from_dict(
trans,
data,
name=name,
exact_tools=exact_tools,
)
if 'uuid' in data:
workflow.uuid = data['uuid']
Expand Down Expand Up @@ -270,7 +272,7 @@ def update_workflow_from_dict(self, trans, stored_workflow, workflow_data):
errors.append( "This workflow contains cycles" )
return workflow, errors

def _workflow_from_dict(self, trans, data, name):
def _workflow_from_dict(self, trans, data, name, exact_tools=False):
if isinstance(data, string_types):
data = json.loads(data)

Expand All @@ -293,7 +295,7 @@ def _workflow_from_dict(self, trans, data, name):
missing_tool_tups = []

for step_dict in self.__walk_step_dicts( data ):
module, step = self.__track_module_from_dict( trans, steps, steps_by_external_id, step_dict )
module, step = self.__track_module_from_dict( trans, steps, steps_by_external_id, step_dict, exact_tools=exact_tools )
is_tool = is_tool_module_type( module.type )
if is_tool and module.tool is None:
# A required tool is not available in the local Galaxy instance.
Expand Down Expand Up @@ -835,8 +837,8 @@ def __walk_step_dicts( self, data ):

yield step_dict

def __track_module_from_dict( self, trans, steps, steps_by_external_id, step_dict ):
module, step = self.__module_from_dict( trans, step_dict )
def __track_module_from_dict( self, trans, steps, steps_by_external_id, step_dict, exact_tools=False ):
module, step = self.__module_from_dict( trans, step_dict, exact_tools=exact_tools )
# Create the model class for the step
steps.append( step )
steps_by_external_id[ step_dict['id' ] ] = step
Expand All @@ -863,7 +865,7 @@ def __track_module_from_dict( self, trans, steps, steps_by_external_id, step_dic
trans.sa_session.add(m)
return module, step

def __module_from_dict( self, trans, step_dict ):
def __module_from_dict( self, trans, step_dict, exact_tools=False ):
""" Create a WorkflowStep model object and corresponding module
representing type-specific functionality from the incoming dictionary.
"""
Expand All @@ -882,7 +884,7 @@ def __module_from_dict( self, trans, step_dict ):
)
step_dict["subworkflow"] = subworkflow

module = module_factory.from_dict( trans, step_dict )
module = module_factory.from_dict( trans, step_dict, exact_tools=exact_tools )
module.save_to_step( step )

annotation = step_dict[ 'annotation' ]
Expand Down
5 changes: 3 additions & 2 deletions lib/galaxy/web/base/controller.py
Expand Up @@ -1165,7 +1165,7 @@ def _import_shared_workflow( self, trans, stored):
session.flush()
return imported_stored

def _workflow_from_dict( self, trans, data, source=None, add_to_menu=False, publish=False ):
def _workflow_from_dict( self, trans, data, source=None, add_to_menu=False, publish=False, exact_tools=False ):
"""
Creates a workflow from a dict. Created workflow is stored in the database and returned.
"""
Expand All @@ -1176,7 +1176,8 @@ def _workflow_from_dict( self, trans, data, source=None, add_to_menu=False, publ
data,
source=source,
add_to_menu=add_to_menu,
publish=publish
publish=publish,
exact_tools=exact_tools,
)
return created_workflow.stored_workflow, created_workflow.missing_tools

Expand Down
4 changes: 4 additions & 0 deletions lib/galaxy/webapps/galaxy/api/workflows.py
Expand Up @@ -402,13 +402,17 @@ def __api_import_new_workflow( self, trans, payload, **kwd ):
publish = util.string_as_bool( payload.get( "publish", False ) )
# If 'publish' set, default to importable.
importable = util.string_as_bool( payload.get( "importable", publish ) )
# Galaxy will try to upgrade tool versions that don't match exactly during import,
# this prevents that.
exact_tools = util.string_as_bool( payload.get( "exact_tools", False ) )

if publish and not importable:
raise exceptions.RequestParameterInvalidException( "Published workflow must be importable." )

from_dict_kwds = dict(
source="API",
publish=publish,
exact_tools=exact_tools,
)
workflow, missing_tool_tups = self._workflow_from_dict( trans, data, **from_dict_kwds )

Expand Down
22 changes: 15 additions & 7 deletions lib/galaxy/workflow/modules.py
Expand Up @@ -52,7 +52,7 @@ def new( Class, trans, content_id=None ):
return Class( trans )

@classmethod
def from_dict( Class, trans, d ):
def from_dict( Class, trans, d, **kwds ):
"""
Create a new instance of the module initialized from values in the
dictionary `d`.
Expand Down Expand Up @@ -195,7 +195,7 @@ def new( Class, trans, content_id=None ):
return module

@classmethod
def from_dict( Class, trans, d ):
def from_dict( Class, trans, d, **kwds ):
module = Class( trans )
state = loads( d["tool_state"] )
module.recover_state( state )
Expand Down Expand Up @@ -283,7 +283,7 @@ def new( Class, trans, content_id=None ):
return module

@classmethod
def from_dict( Class, trans, d ):
def from_dict( Class, trans, d, **kwds ):
module = Class( trans )
if "subworkflow" in d:
module.subworkflow = d["subworkflow"]
Expand Down Expand Up @@ -744,10 +744,17 @@ class ToolModule( WorkflowModule ):

type = "tool"

def __init__( self, trans, tool_id, tool_version=None ):
def __init__( self, trans, tool_id, tool_version=None, exact_tools=False ):
self.trans = trans
self.tool_id = tool_id
self.tool = trans.app.toolbox.get_tool( tool_id, tool_version=tool_version )
tool = trans.app.toolbox.get_tool( tool_id, tool_version=tool_version, exact=exact_tools )
if tool_version and exact_tools and str(tool.version) != str(tool_version):
template = "Exact tool specified during workflow module creation for [%s] but couldn't find correct version [%s]"
message = template % (tool_id, tool_version)
log.debug(message)
tool = None
self.tool = tool

self.post_job_actions = {}
self.runtime_post_job_actions = {}
self.workflow_outputs = []
Expand All @@ -770,14 +777,15 @@ def new( Class, trans, content_id=None ):
return module

@classmethod
def from_dict( Class, trans, d ):
def from_dict( Class, trans, d, **kwds ):
tool_id = d.get( 'content_id', None )
if tool_id is None:
tool_id = d.get( 'tool_id', None ) # Older workflows will have exported this as tool_id.
if tool_id is None:
raise exceptions.RequestParameterInvalidException("No content id could be located for for step [%s]" % d)
tool_version = str( d.get( 'tool_version', None ) )
module = Class( trans, tool_id, tool_version=tool_version )
exact_tools = kwds.get( "exact_tools", False )
module = Class( trans, tool_id, tool_version=tool_version, exact_tools=exact_tools )
module.state = DefaultToolState()
module.label = d.get("label", None) or None
if module.tool is not None:
Expand Down
3 changes: 3 additions & 0 deletions test/base/workflows_format_2/main.py
Expand Up @@ -31,9 +31,12 @@ def convert_and_import_workflow(has_workflow, **kwds):
workflow = yaml_to_workflow(has_workflow, galaxy_interface, workflow_directory)

publish = kwds.get("publish", False)
exact_tools = kwds.get("exact_tools", False)
import_kwds = {}
if publish:
import_kwds["publish"] = True
if exact_tools:
import_kwds["exact_tools"] = True
return galaxy_interface.import_workflow(workflow, **import_kwds)


Expand Down
2 changes: 1 addition & 1 deletion test/unit/workflows/workflow_support.py
Expand Up @@ -63,7 +63,7 @@ class TestToolbox( object ):
def __init__( self ):
self.tools = {}

def get_tool( self, tool_id, tool_version=None ):
def get_tool( self, tool_id, tool_version=None, exact=False ):
# Real tool box returns None of missing tool also
return self.tools.get( tool_id, None )

Expand Down

0 comments on commit a0177fe

Please sign in to comment.