Skip to content

Commit

Permalink
Rebase...
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton committed Sep 21, 2024
1 parent 38b7578 commit 918652e
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 62 deletions.
4 changes: 2 additions & 2 deletions lib/galaxy/tool_util/parameters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
dereference,
encode,
encode_test,
fill_defaults,
fill_static_defaults,
)
from .factory import (
from_input_source,
Expand Down Expand Up @@ -138,7 +138,7 @@
"decode",
"encode",
"encode_test",
"fill_defaults",
"fill_static_defaults",
"dereference",
"WorkflowStepToolState",
"WorkflowStepLinkedToolState",
Expand Down
7 changes: 4 additions & 3 deletions lib/galaxy/tool_util/parameters/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ def encode_callback(parameter: ToolParameterT, value: Any):
return request_state


def fill_defaults(
tool_state: Dict[str, Any], input_models: ToolParameterBundle, partial: bool = True
def fill_static_defaults(
tool_state: Dict[str, Any], input_models: ToolParameterBundle, profile: str, partial: bool = True
) -> Dict[str, Any]:
"""If additional defaults might stem from Galaxy runtime, partial should be true.
Expand Down Expand Up @@ -269,7 +269,8 @@ def _fill_default_for(tool_state: Dict[str, Any], parameter: ToolParameterT) ->
# even optional parameters default to false if not in the body of the request :_(
# see test_tools.py -> expression_null_handling_boolean or test cases for gx_boolean_optional.xml
tool_state[parameter_name] = boolean.value or False
if parameter_type in ["gx_integer", "gx_float", "gx_hidden", "gx_data_column"]:

if parameter_type in ["gx_integer", "gx_float", "gx_hidden"]:
has_value_parameter = cast(
Union[
IntegerParameterModel,
Expand Down
30 changes: 16 additions & 14 deletions lib/galaxy/tool_util/parameters/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def get_color_value(input_source: InputSource) -> str:
return input_source.get("value", "#000000")


def _from_input_source_galaxy(input_source: InputSource) -> ToolParameterT:
def _from_input_source_galaxy(input_source: InputSource, profile: str) -> ToolParameterT:
input_type = input_source.parse_input_type()
if input_type == "param":
param_type = input_source.get("type")
Expand Down Expand Up @@ -180,8 +180,8 @@ def _from_input_source_galaxy(input_source: InputSource) -> ToolParameterT:
multiple = input_source.get_bool("multiple", False)
optional = input_source.parse_optional()
value = input_source.parse_data_column_value()
accept_default = (
input_source.get("accept_default", False) or not multiple
accept_default = input_source.get("accept_default", False) or (
not multiple and profile < "20.01"
) # wild but that is what the tests say I think
if value is None and accept_default:
if multiple:
Expand Down Expand Up @@ -224,7 +224,8 @@ def _from_input_source_galaxy(input_source: InputSource) -> ToolParameterT:
elif input_type == "conditional":
test_param_input_source = input_source.parse_test_input_source()
test_parameter = cast(
Union[BooleanParameterModel, SelectParameterModel], _from_input_source_galaxy(test_param_input_source)
Union[BooleanParameterModel, SelectParameterModel],
_from_input_source_galaxy(test_param_input_source, profile),
)
whens = []
default_test_value = cond_test_parameter_default_value(test_parameter)
Expand All @@ -235,7 +236,7 @@ def _from_input_source_galaxy(input_source: InputSource) -> ToolParameterT:
else:
typed_value = value

tool_parameter_models = input_models_for_page(case_inputs_sources)
tool_parameter_models = input_models_for_page(case_inputs_sources, profile)
is_default_when = False
if typed_value == default_test_value:
is_default_when = True
Expand All @@ -254,7 +255,7 @@ def _from_input_source_galaxy(input_source: InputSource) -> ToolParameterT:
# title = input_source.get("title")
# help = input_source.get("help", None)
instance_sources = input_source.parse_nested_inputs_source()
instance_tool_parameter_models = input_models_for_page(instance_sources)
instance_tool_parameter_models = input_models_for_page(instance_sources, profile)
min_raw = input_source.get("min", None)
max_raw = input_source.get("max", None)
min = int(min_raw) if min_raw is not None else None
Expand All @@ -268,7 +269,7 @@ def _from_input_source_galaxy(input_source: InputSource) -> ToolParameterT:
elif input_type == "section":
name = input_source.get("name")
instance_sources = input_source.parse_nested_inputs_source()
instance_tool_parameter_models = input_models_for_page(instance_sources)
instance_tool_parameter_models = input_models_for_page(instance_sources, profile)
return SectionParameterModel(
name=name,
parameters=instance_tool_parameter_models,
Expand Down Expand Up @@ -341,34 +342,35 @@ def tool_parameter_bundle_from_json(json: Dict[str, Any]) -> ToolParameterBundle

def input_models_for_tool_source(tool_source: ToolSource) -> ToolParameterBundleModel:
pages = tool_source.parse_input_pages()
return ToolParameterBundleModel(parameters=input_models_for_pages(pages))
profile = tool_source.parse_profile()
return ToolParameterBundleModel(parameters=input_models_for_pages(pages, profile))


def input_models_for_pages(pages: PagesSource) -> List[ToolParameterT]:
def input_models_for_pages(pages: PagesSource, profile: str) -> List[ToolParameterT]:
input_models = []
if pages.inputs_defined:
for page_source in pages.page_sources:
input_models.extend(input_models_for_page(page_source))
input_models.extend(input_models_for_page(page_source, profile))

return input_models


def input_models_for_page(page_source: PageSource) -> List[ToolParameterT]:
def input_models_for_page(page_source: PageSource, profile: str) -> List[ToolParameterT]:
input_models = []
for input_source in page_source.parse_input_sources():
input_type = input_source.parse_input_type()
if input_type == "display":
# not a real input... just skip this. Should this be handled in the parser layer better?
continue
tool_parameter_model = from_input_source(input_source)
tool_parameter_model = from_input_source(input_source, profile)
input_models.append(tool_parameter_model)
return input_models


def from_input_source(input_source: InputSource) -> ToolParameterT:
def from_input_source(input_source: InputSource, profile: str) -> ToolParameterT:
tool_parameter: ToolParameterT
if isinstance(input_source, CwlInputSource):
tool_parameter = _from_input_source_cwl(input_source)
else:
tool_parameter = _from_input_source_galaxy(input_source)
tool_parameter = _from_input_source_galaxy(input_source, profile)
return tool_parameter
4 changes: 3 additions & 1 deletion lib/galaxy/tool_util/parser/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,9 @@ def to_element(xml_element_dict: "TestCollectionDefElementInternal") -> "JsonTes
identifier=identifier, **element_object._test_format_to_dict()
)
else:
input_as_dict: Optional[JsonTestDatasetDefDict] = xml_data_input_to_json(cast(ToolSourceTestInput, element_object))
input_as_dict: Optional[JsonTestDatasetDefDict] = xml_data_input_to_json(
cast(ToolSourceTestInput, element_object)
)
if input_as_dict is not None:
as_dict = JsonTestCollectionDefDatasetElementDict(
identifier=identifier,
Expand Down
3 changes: 2 additions & 1 deletion lib/galaxy/tool_util/verify/interactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,8 @@ def adapt_collections(test_input: JsonTestCollectionDefDict) -> DataCollectionRe
if not successful:
request = self.get_tool_request(tool_request_id) or {}
raise RunToolException(
f"Tool request failure - state {request.get('state')}, message: {request.get('state_message')}", inputs_tree
f"Tool request failure - state {request.get('state')}, message: {request.get('state_message')}",
inputs_tree,
)
jobs = self.jobs_for_tool_request(tool_request_id)
outputs = OutputsDict()
Expand Down
11 changes: 6 additions & 5 deletions lib/galaxy/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
)
from galaxy.tool_util.output_checker import DETECTED_JOB_STATE
from galaxy.tool_util.parameters import (
fill_defaults,
fill_static_defaults,
input_models_for_pages,
JobInternalToolState,
RequestInternalDereferencedToolState,
Expand Down Expand Up @@ -127,6 +127,7 @@
from galaxy.tools.imp_exp import JobImportHistoryArchiveWrapper
from galaxy.tools.parameters import (
check_param,
fill_dynamic_defaults,
params_from_strings,
params_to_incoming,
params_to_json,
Expand Down Expand Up @@ -1439,7 +1440,7 @@ def parse_inputs(self, tool_source: ToolSource):
pages = tool_source.parse_input_pages()
enctypes: Set[str] = set()
try:
parameters = input_models_for_pages(pages)
parameters = input_models_for_pages(pages, tool_source.parse_profile())
self.parameters = parameters
except Exception:
pass
Expand Down Expand Up @@ -1874,10 +1875,10 @@ def expand_incoming_async(
all_params: List[ToolStateJobInstancePopulatedT] = []
internal_states: List[JobInternalToolState] = []
for expanded_incoming in job_tool_states:
expanded_incoming = fill_defaults(expanded_incoming, self)
expanded_incoming = fill_static_defaults(expanded_incoming, self, self.profile)
fill_dynamic_defaults(request_context, self.inputs, expanded_incoming)
internal_tool_state = JobInternalToolState(expanded_incoming)
# internal_tool_state.validate(self)
# some defaults might not be available until populate runs...
internal_tool_state.validate(self)
internal_states.append(internal_tool_state)
params, errors = self._populate(request_context, expanded_incoming, "21.01")

Expand Down
52 changes: 52 additions & 0 deletions lib/galaxy/tools/parameters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,58 @@ def _populate_state_legacy(
state[input.name] = value


def fill_dynamic_defaults(
request_context,
inputs: ToolInputsT,
incoming: ToolStateJobInstanceT,
):
"""
Expands incoming parameters with default values.
"""
for input in inputs.values():
if input.type == "repeat":
repeat_input = cast(Repeat, input)
for rep in incoming[repeat_input.name]:
fill_dynamic_defaults(
request_context,
repeat_input.inputs,
rep,
)

elif input.type == "conditional":
conditional_input = cast(Conditional, input)
test_param = cast(ToolParameter, conditional_input.test_param)
test_param_value = incoming.get(conditional_input.name, {}).get(test_param.name)
try:
current_case = conditional_input.get_current_case(test_param_value)
fill_dynamic_defaults(
request_context,
conditional_input.cases[current_case].inputs,
cast(ToolStateJobInstanceT, incoming.get(conditional_input.name)),
)
except Exception:
raise Exception("The selected case is unavailable/invalid.")

elif input.type == "section":
section_input = cast(Section, input)
fill_dynamic_defaults(
request_context,
section_input.inputs,
cast(ToolStateJobInstanceT, incoming.get(section_input.name)),
)
if section_errors:
errors[section_input.name] = section_errors

elif input.type == "upload_dataset":
raise NotImplementedError

else:
if input.name not in incoming:
context = ExpressionContext(incoming, context)
param_value = input.get_initial_value(request_context, context)
incoming[input.name] = param_value


def _get_incoming_value(incoming, key, default):
"""
Fetch value from incoming dict directly or check special nginx upload
Expand Down
1 change: 1 addition & 0 deletions test/functional/tools/select_optional.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<tool id="select_optional" name="Optional select" version="1.0.0" profile="20.01">
<!-- this tool has a profile of 20.01, but has an identical behavior without it -->
<command><![CDATA[
echo select_opt $select_opt >> '$output1' &&
echo select_mult_opt $select_mult_opt >> '$output1' &&
Expand Down
73 changes: 37 additions & 36 deletions test/unit/tool_util/test_parameter_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
decode,
dereference,
encode,
fill_defaults,
fill_static_defaults,
input_models_for_tool_source,
RequestInternalDereferencedToolState,
RequestInternalToolState,
Expand Down Expand Up @@ -178,41 +178,42 @@ def test_fill_defaults():

# These two don't validate as expected - see last test case in gx_data_column.xml & gx_data_column_multiple.xml
# and API test case test_data_column_defaults
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column", partial=True
)
assert with_defaults["parameter"] == 1
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple", partial=True
)
assert with_defaults["parameter"] is None

with_defaults = fill_state_for({"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_with_default")
assert with_defaults["parameter"] == 2
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_with_default_legacy"
)
assert with_defaults["parameter"] == 3
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_accept_default"
)
assert with_defaults["parameter"] == 1
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_optional_accept_default"
)
assert with_defaults["parameter"] == 1
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple_accept_default"
)
assert with_defaults["parameter"] == [1]
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple_with_default"
)
assert with_defaults["parameter"] == [1, 2]
with_defaults = fill_state_for(
{"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple_optional_with_default"
)
assert with_defaults["parameter"] == [1, 2]
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column", partial=True
# )
# assert with_defaults["parameter"] == 1
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple", partial=True
# )
# assert with_defaults["parameter"] is None

# with_defaults = fill_state_for({"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_with_default")
# assert with_defaults["parameter"] == 2
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_with_default_legacy"
# )
# assert with_defaults["parameter"] == 3
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_accept_default"
# )
# assert with_defaults["parameter"] == 1
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_optional_accept_default"
# )
# assert with_defaults["parameter"] == 1
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple_accept_default"
# )
# assert with_defaults["parameter"] == [1]
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple_with_default"
# )
# assert with_defaults["parameter"] == [1, 2]
# with_defaults = fill_state_for(
# {"ref_parameter": {"src": "hda", "id": 5}}, "parameters/gx_data_column_multiple_optional_with_default"
# )
# assert with_defaults["parameter"] == [1, 2]

with_defaults = fill_state_for({}, "parameters/gx_select")
assert with_defaults["parameter"] == "--ex1"
Expand Down Expand Up @@ -247,5 +248,5 @@ def _fake_encode(input: int) -> str:
def fill_state_for(tool_state: Dict[str, Any], tool_path: str, partial: bool = False) -> Dict[str, Any]:
tool_source = tool_source_for(tool_path)
bundle = input_models_for_tool_source(tool_source)
internal_state = fill_defaults(tool_state, bundle, partial=partial)
internal_state = fill_static_defaults(tool_state, bundle, tool_source.parse_profile(), partial=partial)
return internal_state

0 comments on commit 918652e

Please sign in to comment.