Skip to content

Commit

Permalink
Merge pull request galaxyproject#18900 from mvdbeek/access_tool_data_…
Browse files Browse the repository at this point in the history
…table_filters_in_workflow_building_mode

[24.1] Access tool data table filters in workflow building mode
  • Loading branch information
mvdbeek authored Sep 30, 2024
2 parents d914cac + b5d46aa commit 662aed0
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 13 deletions.
10 changes: 10 additions & 0 deletions lib/galaxy/managers/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@
import string
from json import dumps
from typing import (
Any,
Callable,
cast,
Dict,
List,
Optional,
Tuple,
)

from sqlalchemy import select
Expand Down Expand Up @@ -204,6 +207,13 @@ class ProvidesUserContext(ProvidesAppContext):

galaxy_session: Optional[GalaxySession] = None
_tag_handler: Optional[GalaxyTagHandlerSession] = None
_short_term_cache: Dict[Tuple[str, ...], Any]

def set_cache_value(self, args: Tuple[str, ...], value: Any):
self._short_term_cache[args] = value

def get_cache_value(self, args: Tuple[str, ...], default: Any = None) -> Any:
return self._short_term_cache.get(args, default)

@property
def tag_handler(self):
Expand Down
11 changes: 11 additions & 0 deletions lib/galaxy/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3670,6 +3670,17 @@ def element_is_valid(element: model.DatasetCollectionElement):
return False


class FilterNullTool(FilterDatasetsTool):
tool_type = "filter_null"
require_dataset_ok = True

@staticmethod
def element_is_valid(element: model.DatasetCollectionElement):
element_object = element.element_object
assert isinstance(element_object, model.DatasetInstance)
return element_object.extension == "expression.json" and element_object.blurb == "skipped"


class FlattenTool(DatabaseOperationTool):
tool_type = "flatten_collection"
require_terminal_states = False
Expand Down
12 changes: 6 additions & 6 deletions lib/galaxy/tools/parameters/dynamic_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,12 @@ def get_dependency_name(self):
return self.ref_name

def filter_options(self, options, trans, other_values):
if trans is not None and trans.workflow_building_mode:
return []
ref = other_values.get(self.ref_name, None)
if ref is None:
if ref is None or is_runtime_value(ref):
ref = []

# - for HDCAs the list of contained HDAs is extracted
# - single values are transformed in a single eleent list
# - single values are transformed in a single element list
# - remaining cases are already lists (select and data parameters with multiple=true)
if isinstance(ref, HistoryDatasetCollectionAssociation):
ref = ref.to_hda_representative(multiple=True)
Expand Down Expand Up @@ -835,6 +833,9 @@ def get_field_by_name_for_value(self, field_name, value, trans, other_values):
return rval

def get_options(self, trans, other_values):

rval = []

def to_triple(values):
if len(values) == 2:
return [str(values[0]), str(values[1]), False]
Expand Down Expand Up @@ -877,8 +878,7 @@ def to_triple(values):
data = []

# We only support the very specific ["name", "value", "selected"] format for now.
return [to_triple(d) for d in data]
rval = []
rval = [to_triple(d) for d in data]
if (
self.file_fields is not None
or self.tool_data_table is not None
Expand Down
2 changes: 2 additions & 0 deletions lib/galaxy/webapps/base/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
Any,
Dict,
Optional,
Tuple,
)
from urllib.parse import urlparse

Expand Down Expand Up @@ -325,6 +326,7 @@ def __init__(
self.galaxy_session = None
self.error_message = None
self.host = self.request.host
self._short_term_cache: Dict[Tuple[str, ...], Any] = {}

# set any cross origin resource sharing headers if configured to do so
self.set_cors_headers()
Expand Down
6 changes: 0 additions & 6 deletions lib/galaxy/work/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,6 @@ def __init__(
self.workflow_building_mode = workflow_building_mode
self.galaxy_session = galaxy_session

def set_cache_value(self, args: Tuple[str, ...], value: Any):
self._short_term_cache[args] = value

def get_cache_value(self, args: Tuple[str, ...], default: Any = None) -> Any:
return self._short_term_cache.get(args, default)

@property
def app(self):
return self._app
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/workflow/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -1414,7 +1414,7 @@ def restrict_options(self, step, connections: Iterable[WorkflowStepConnection],

def callback(input, prefixed_name, context, **kwargs):
if prefixed_name == connection.input_name and hasattr(input, "get_options"): # noqa: B023
static_options.append(input.get_options(self.trans, {}))
static_options.append(input.get_options(self.trans, context))

visit_input_values(tool_inputs, module.state.inputs, callback)
elif isinstance(module, SubWorkflowModule):
Expand Down
19 changes: 19 additions & 0 deletions lib/galaxy_test/api/test_workflow_build_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from galaxy_test.base.populators import (
skip_without_tool,
WorkflowPopulator,
)
from ._framework import ApiTestCase


class TestBuildWorkflowModule(ApiTestCase):

def setUp(self):
super().setUp()
self.workflow_populator = WorkflowPopulator(self.galaxy_interactor)

@skip_without_tool("select_from_url")
def test_build_module_filter_dynamic_select(self):
# Verify that filtering on parameters that depend on parameter and validators works
# fine in workflow building mode.
module = self.workflow_populator.build_module(step_type="tool", content_id="select_from_url")
assert not module["errors"], module["errors"]
6 changes: 6 additions & 0 deletions lib/galaxy_test/base/populators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2298,6 +2298,12 @@ def import_tool(self, tool) -> Dict[str, Any]:
assert upload_response.status_code == 200, upload_response
return upload_response.json()

def build_module(self, step_type: str, content_id: Optional[str] = None, inputs: Optional[Dict[str, Any]] = None):
payload = {"inputs": inputs or {}, "type": step_type, "content_id": content_id}
response = self._post("workflows/build_module", data=payload, json=True)
assert response.status_code == 200, response
return response.json()

def _import_tool_response(self, tool) -> Response:
using_requirement("admin")
tool_str = json.dumps(tool, indent=4)
Expand Down
7 changes: 7 additions & 0 deletions test/functional/tools/select_from_url.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ echo '$url_param_value_header_and_body' > '$param_value_header_and_body'
<options from_url="https://usegalaxy.org/api/genomes">
</options>
</param>
<param name="dynamic_param_filtered_with_validator" type="select">
<!-- tested in test_build_module_filter_dynamic_select -->
<options from_url="https://usegalaxy.org/api/genomes">
<filter type="param_value" ref="url_param_value" column="1" />
</options>
<validator type="no_options" message="Need at least one option here" />
</param>
<!--
<param name="url_param_value_templated" type="select">
<options from_url="http://localhost:8000/data?user=$__user_id__">
Expand Down

0 comments on commit 662aed0

Please sign in to comment.