Skip to content

Commit

Permalink
Merge pull request #19097 from davelopez/support_deferred_datasets_in…
Browse files Browse the repository at this point in the history
…_visualizations

Support deferred datasets in visualizations
  • Loading branch information
guerler authored Nov 4, 2024
2 parents a5aaa1c + 688b08a commit 1b4dd45
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const showRerun = computed(() => {
});
const showVisualizations = computed(() => {
// TODO: Check hasViz, if visualizations are activated in the config
return !props.item.purged && ["ok", "failed_metadata", "error"].includes(props.item.state);
return !props.item.purged && ["ok", "failed_metadata", "error", "deferred"].includes(props.item.state);
});
const reportErrorUrl = computed(() => {
return prependPath(props.itemUrls.reportError!);
Expand Down
13 changes: 10 additions & 3 deletions config/plugins/visualizations/visualization.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,18 @@
if result_type is 'datatype' the registry will assume the text is a datatype class name
and parse it into the proper class before the test (often 'isinstance') is run.
DEFAULT: no parsing (result should be a string)
allow_uri_if_protocol: used in conjunction with type='isinstance' and test_attr='datatype'. Let you define
a list of protocols or schemes (e.g. 's3,https') that, in the case of a deferred target (e.g. currently only HDAs),
the registry will allow the test to pass if the the source URI has a scheme in the list.
This is useful for visualizations that can work directly with URIs.
DEFAULT: []

-->
<!ATTLIST test
type CDATA #IMPLIED
test_attr CDATA #IMPLIED
result_type CDATA #IMPLIED
type CDATA #IMPLIED
test_attr CDATA #IMPLIED
result_type CDATA #IMPLIED
allow_uri_if_protocol CDATA #IMPLIED
>

<!ELEMENT to_param (#PCDATA)>
Expand Down
23 changes: 21 additions & 2 deletions lib/galaxy/visualization/plugins/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
)

import galaxy.model
from galaxy.util import asbool
from galaxy.util import (
asbool,
listify,
)
from galaxy.util.xml_macros import load

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -301,8 +304,16 @@ def parse_tests(self, xml_tree_list):
# result type should tell the registry how to convert the result before the test
test_result_type = test_elem.get("result_type", "string")

# allow_uri_if_protocol indicates that the visualization can work with deferred data_sources which source URI
# matches any of the given protocols in this list. This is useful for visualizations that can work with URIs.
# Can only be used with isinstance tests. By default, an empty list means that the visualization doesn't support
# deferred data_sources.
allow_uri_if_protocol = []

# test functions should be sent an object to test, and the parsed result expected from the test
if test_type == "isinstance":
allow_uri_if_protocol = listify(test_elem.get("allow_uri_if_protocol"))

# is test_attr attribute an instance of result
# TODO: wish we could take this further but it would mean passing in the datatypes_registry
def test_fn(o, result, getter=getter):
Expand All @@ -328,7 +339,15 @@ def test_fn(o, result, getter=getter):
def test_fn(o, result, getter=getter):
return str(getter(o)) == result

tests.append({"type": test_type, "result": test_result, "result_type": test_result_type, "fn": test_fn})
tests.append(
{
"type": test_type,
"result": test_result,
"result_type": test_result_type,
"fn": test_fn,
"allow_uri_if_protocol": allow_uri_if_protocol,
}
)

return tests

Expand Down
35 changes: 34 additions & 1 deletion lib/galaxy/visualization/plugins/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import logging
import os
import weakref
from typing import (
List,
Optional,
)

from galaxy.exceptions import ObjectNotFound
from galaxy.util import (
Expand Down Expand Up @@ -268,6 +272,7 @@ def is_object_applicable(self, trans, target_object, data_source_tests):
result_type = test["result_type"]
test_result = test["result"]
test_fn = test["fn"]
supported_protocols = test.get("allow_uri_if_protocol", [])
# log.debug( '%s %s: %s, %s, %s, %s', str( target_object ), 'is_object_applicable',
# test_type, result_type, test_result, test_fn )

Expand All @@ -286,8 +291,36 @@ def is_object_applicable(self, trans, target_object, data_source_tests):
continue

# NOTE: tests are OR'd, if any test passes - the visualization can be applied
if test_fn(target_object, test_result):
if test_fn(target_object, test_result) and self._check_uri_support(target_object, supported_protocols):
# log.debug( '\t test passed' )
return True

return False

def _is_deferred(self, target_object) -> bool:
"""Whether the target object is a deferred object."""
return getattr(target_object, "state", None) == "deferred"

def _deferred_source_uri(self, target_object) -> Optional[str]:
"""Get the source uri from a deferred object."""
sources = getattr(target_object, "sources", None)
if sources and sources[0]:
return sources[0].source_uri
return None

def _check_uri_support(self, target_object, supported_protocols: List[str]) -> bool:
"""Test if the target object is deferred and has a supported protocol."""
if not self._is_deferred(target_object):
return True # not deferred, so no uri to check

if not supported_protocols:
return False # no protocols defined, means no support for deferred objects

if "*" in supported_protocols:
return True # wildcard support for all protocols

deferred_source_uri = self._deferred_source_uri(target_object)
if deferred_source_uri:
protocol = deferred_source_uri.split("://")[0]
return protocol in supported_protocols
return False

0 comments on commit 1b4dd45

Please sign in to comment.