Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement default locations for data and collection parameters. #14955

Merged
merged 5 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions lib/galaxy/managers/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ def _workflow_to_dict_run(self, trans, stored, workflow, history=None):
for pja in step.post_job_actions
]
else:
inputs = step.module.get_runtime_inputs(connections=step.output_connections)
inputs = step.module.get_runtime_inputs(step, connections=step.output_connections)
step_model = {"inputs": [input.to_dict(trans) for input in inputs.values()]}
step_model["when"] = step.when_expression
step_model["replacement_parameters"] = step.module.get_informal_replacement_parameters(step)
Expand Down Expand Up @@ -1121,7 +1121,7 @@ def do_inputs(inputs, values, prefix, step, other_values=None):
else:
module = step.module
step_dict["label"] = module.name
step_dict["inputs"] = do_inputs(module.get_runtime_inputs(), step.state.inputs, "", step)
step_dict["inputs"] = do_inputs(module.get_runtime_inputs(step), step.state.inputs, "", step)
step_dicts.append(step_dict)
return {
"name": workflow.name,
Expand Down Expand Up @@ -1770,6 +1770,11 @@ def __module_from_dict(

if "in" in step_dict:
for input_name, input_dict in step_dict["in"].items():
# This is just a bug in gxformat? I think the input
# defaults should be called input to match the input modules's
# input parameter name.
if input_name == "default":
input_name = "input"
step_input = step.get_or_add_input(input_name)
NO_DEFAULT_DEFINED = object()
default = input_dict.get("default", NO_DEFAULT_DEFINED)
Expand Down
18 changes: 14 additions & 4 deletions lib/galaxy/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7625,10 +7625,20 @@ def input_type(self):

@property
def input_default_value(self):
tool_state = self.tool_inputs
default_value = tool_state.get("default")
if default_value:
default_value = json.loads(default_value)["value"]
self.get_input_default_value(None)

def get_input_default_value(self, default_default):
# parameter_input and the data parameters handle this slightly differently
# unfortunately.
if self.type == "parameter_input":
tool_state = self.tool_inputs
default_value = tool_state.get("default", default_default)
else:
default_value = default_default
for step_input in self.inputs:
if step_input.name == "input" and step_input.default_value_set:
default_value = step_input.default_value
break
return default_value

@property
Expand Down
3 changes: 3 additions & 0 deletions lib/galaxy/tool_util/parser/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@ def parse_test_input_source(self) -> "InputSource":
def parse_when_input_sources(self):
raise NotImplementedError(NOT_IMPLEMENTED_MESSAGE)

def parse_default(self) -> Optional[Dict[str, Any]]:
return None


class PageSource(metaclass=ABCMeta):
def parse_display(self):
Expand Down
52 changes: 52 additions & 0 deletions lib/galaxy/tool_util/parser/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import re
import uuid
from typing import (
Any,
cast,
Dict,
Iterable,
List,
Optional,
Expand Down Expand Up @@ -1274,6 +1276,56 @@ def parse_when_input_sources(self):
sources.append((value, case_page_source))
return sources

def parse_default(self) -> Optional[Dict[str, Any]]:
def file_default_from_elem(elem):
# TODO: hashes, created_from_basename, etc...
return {"class": "File", "location": elem.get("location")}

def read_elements(collection_elem):
element_dicts = []
elements = collection_elem.findall("element")
for element in elements:
identifier = element.get("name")
subcollection_elem = element.find("collection")
if subcollection_elem:
collection_type = subcollection_elem.get("collection_type")
element_dicts.append(
{
"class": "Collection",
"identifier": identifier,
"collection_type": collection_type,
"elements": read_elements(subcollection_elem),
}
)
else:
element_dict = file_default_from_elem(element)
element_dict["identifier"] = identifier
element_dicts.append(element_dict)
return element_dicts

elem = self.input_elem
element_type = self.input_elem.get("type")
if element_type == "data":
default_elem = elem.find("default")
if default_elem is not None:
return file_default_from_elem(default_elem)
else:
return None
else:
default_elem = elem.find("default")
if default_elem is not None:
default_elem = elem.find("default")
collection_type = default_elem.get("collection_type")
name = default_elem.get("name", elem.get("name"))
return {
"class": "Collection",
"name": name,
"collection_type": collection_type,
"elements": read_elements(default_elem),
}
else:
return None


class ParallelismInfo:
"""
Expand Down
7 changes: 7 additions & 0 deletions lib/galaxy/tool_util/parser/yaml.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import json
from typing import (
Any,
Dict,
List,
Optional,
)

import packaging.version
Expand Down Expand Up @@ -358,6 +360,11 @@ def parse_static_options(self):
static_options.append((label, value, selected))
return static_options

def parse_default(self) -> Optional[Dict[str, Any]]:
input_dict = self.input_dict
default_def = input_dict.get("default", None)
return default_def


def _ensure_has(dict, defaults):
for key, value in defaults.items():
Expand Down
68 changes: 68 additions & 0 deletions lib/galaxy/tool_util/xsd/galaxy.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -3731,6 +3731,7 @@ allow access to Python code to generate options for a select list. See
<xs:element name="options" type="ParamOptions"/>
<xs:element name="validator" type="Validator" />
<xs:element name="sanitizer" type="Sanitizer"/>
<xs:element name="default" type="ParamDefault" />
<xs:element name="help" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">Documentation for help</xs:documentation>
Expand Down Expand Up @@ -4115,6 +4116,73 @@ dataset for the contained input of the type specified using the ``type`` tag.
</xs:attribute>
</xs:complexType>

<xs:complexType name="ParamDefault">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
]]>
</xs:documentation>
</xs:annotation>
<xs:sequence>
<!-- can have zero or one collection elements -->
<xs:element name="element" type="ParamDefaultElement" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="collection_type" type="CollectionType" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Collection type for default collection (if param type is data_collection). Simple collection types are
either ``list`` or ``paired``, nested collections are specified as colon separated list of simple
collection types (the most common types are ``list``, ``paired``,
``list:paired``, or ``list:list``).
]]></xs:documentation>
</xs:annotation>
</xs:attribute>

<xs:attribute name="location" type="xs:anyURI" gxdocs:added="23.2" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Galaxy-aware URI for the default file. This should only be used with parameters of type "data".
]]></xs:documentation>
</xs:annotation>
</xs:attribute>

</xs:complexType>

<xs:complexType name="ParamDefaultCollection">
<xs:sequence>
<xs:element name="element" type="ParamDefaultElement" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>

<xs:attribute name="collection_type" type="CollectionType" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Collection type for default collection (if param type is data_collection). Simple collection types are
either ``list`` or ``paired``, nested collections are specified as colon separated list of simple
collection types (the most common types are ``list``, ``paired``,
``list:paired``, or ``list:list``).
]]></xs:documentation>
</xs:annotation>
</xs:attribute>

</xs:complexType>

<xs:complexType name="ParamDefaultElement">
<xs:sequence>
<xs:element name="collection" type="ParamDefaultCollection" minOccurs="0" maxOccurs="1" />
</xs:sequence>
<xs:attribute name="name" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="en">Name (and element identifier) for this element</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="location" type="xs:anyURI" gxdocs:added="23.2" use="optional">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Galaxy-aware URI for the default file for collection element.
]]></xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>

<xs:complexType name="ParamOptions">
<xs:annotation>
<xs:documentation xml:lang="en"><![CDATA[
Expand Down
Loading
Loading