Skip to content

Commit

Permalink
Add support for URI protocols in visualization datatype checks
Browse files Browse the repository at this point in the history
  • Loading branch information
davelopez committed Nov 2, 2024
1 parent 89184e6 commit 3c60637
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 17 deletions.
15 changes: 8 additions & 7 deletions config/plugins/visualizations/visualization.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +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_deferred: used in conjunction with type='isinstance' and test_attr='datatype'. If set to true,
the registry will allow the test to pass if the target is deferred (currently only HDAs can be deferred).
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: false
DEFAULT: []

-->
<!ATTLIST test
type CDATA #IMPLIED
test_attr CDATA #IMPLIED
result_type CDATA #IMPLIED
allow_deferred 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
17 changes: 11 additions & 6 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,13 +304,15 @@ 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_deferred indicates that the visualization can work with deferred data_sources
# Can only be used with isinstance tests. By default, no visualization can work with deferred data_sources.
allow_deferred = False
# 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_deferred = asbool(test_elem.get("allow_deferred", False))
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
Expand Down Expand Up @@ -340,7 +345,7 @@ def test_fn(o, result, getter=getter):
"result": test_result,
"result_type": test_result_type,
"fn": test_fn,
"allow_deferred": allow_deferred,
"allow_uri_if_protocol": allow_uri_if_protocol,
}
)

Expand Down
33 changes: 29 additions & 4 deletions 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 @@ -263,13 +267,12 @@ def is_object_applicable(self, trans, target_object, data_source_tests):
it can be applied to the target_object.
"""
# log.debug( 'is_object_applicable( self, trans, %s, %s )', target_object, data_source_tests )
is_deferred_target = self._is_deferred(target_object)
for test in data_source_tests:
test_type = test["type"]
result_type = test["result_type"]
test_result = test["result"]
test_fn = test["fn"]
allow_deferred = test.get("allow_deferred", False)
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 @@ -288,11 +291,33 @@ 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) and (not is_deferred_target or allow_deferred):
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):
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

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 3c60637

Please sign in to comment.