Skip to content

Commit e4aff2c

Browse files
committed
Stock tools.
1 parent 5faecde commit e4aff2c

File tree

5 files changed

+102
-3
lines changed

5 files changed

+102
-3
lines changed

lib/galaxy/tools/stock.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Reason about stock tools based on ToolSource abstractions."""
2+
3+
from pathlib import Path
4+
5+
from lxml.etree import XMLSyntaxError
6+
7+
# Set GALAXY_INCLUDES_ROOT from tool shed to point this at a Galaxy root
8+
# (once we are running the tool shed from packages not rooted with Galaxy).
9+
import galaxy.tools
10+
from galaxy.tool_util.parser import get_tool_source
11+
from galaxy.util import galaxy_directory
12+
from galaxy.util.resources import files
13+
14+
15+
def stock_tool_paths():
16+
yield from _walk_directory_for_tools(files(galaxy.tools))
17+
yield from _walk_directory_for_tools(Path(galaxy_directory()) / "test" / "functional" / "tools")
18+
19+
20+
def stock_tool_sources():
21+
for stock_tool_path in stock_tool_paths():
22+
try:
23+
yield get_tool_source(str(stock_tool_path))
24+
except XMLSyntaxError:
25+
continue
26+
27+
28+
def _walk_directory_for_tools(path):
29+
if path.is_file() and path.name.endswith(".xml"):
30+
yield path
31+
elif path.is_dir():
32+
for directory in path.iterdir():
33+
yield from _walk_directory_for_tools(directory)

lib/galaxy/util/__init__.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,12 +1738,20 @@ def safe_str_cmp(a, b):
17381738
return rv == 0
17391739

17401740

1741+
# never load packages this way (won't work for installed packages),
1742+
# but while we're working on packaging everything this can be a way to point
1743+
# an installed Galaxy at a Galaxy root for things like tools. Ultimately
1744+
# this all needs to be packaged, but we have some very old PRs working on this
1745+
# that are pretty tricky and shouldn't slow current development.
1746+
GALAXY_INCLUDES_ROOT = os.environ.get("GALAXY_INCLUDES_ROOT")
1747+
1748+
17411749
# Don't use this directly, prefer method version that "works" with packaged Galaxy.
1742-
galaxy_root_path = Path(__file__).parent.parent.parent.parent
1750+
galaxy_root_path = Path(GALAXY_INCLUDES_ROOT) if GALAXY_INCLUDES_ROOT else Path(__file__).parent.parent.parent.parent
17431751

17441752

17451753
def galaxy_directory() -> str:
1746-
if in_packages():
1754+
if in_packages() and not GALAXY_INCLUDES_ROOT:
17471755
# This will work only when running pytest from <galaxy_root>/packages/<package_name>/
17481756
cwd = Path.cwd()
17491757
path = cwd.parent.parent

lib/tool_shed/managers/tools.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import tempfile
33
from collections import namedtuple
44
from typing import (
5+
Dict,
56
List,
67
Optional,
78
Tuple,
@@ -27,6 +28,7 @@
2728
get_tool_source,
2829
ToolSource,
2930
)
31+
from galaxy.tools.stock import stock_tool_sources
3032
from tool_shed.context import (
3133
ProvidesRepositoriesContext,
3234
SessionRequestContext,
@@ -36,6 +38,8 @@
3638
from tool_shed.webapp.search.tool_search import ToolSearch
3739
from .trs import trs_tool_id_to_repository_metadata
3840

41+
STOCK_TOOL_SOURCES: Optional[Dict[str, Dict[str, ToolSource]]] = None
42+
3943

4044
def search(trans: SessionRequestContext, q: str, page: int = 1, page_size: int = 10) -> dict:
4145
"""
@@ -114,6 +118,18 @@ def tool_input_models_for(
114118

115119
def tool_source_for(
116120
trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
121+
) -> ToolSource:
122+
if "~" in trs_tool_id:
123+
return _shed_tool_source_for(trans, trs_tool_id, tool_version, repository_clone_url)
124+
else:
125+
tool_source = _stock_tool_source_for(trs_tool_id, tool_version)
126+
if tool_source is None:
127+
raise ObjectNotFound()
128+
return tool_source
129+
130+
131+
def _shed_tool_source_for(
132+
trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
117133
) -> ToolSource:
118134
rval = get_repository_metadata_tool_dict(trans, trs_tool_id, tool_version)
119135
repository_metadata, tool_version_metadata = rval
@@ -133,3 +149,24 @@ def tool_source_for(
133149
return tool_source
134150
finally:
135151
remove_dir(work_dir)
152+
153+
154+
def _stock_tool_source_for(tool_id: str, tool_version: str) -> Optional[ToolSource]:
155+
_init_stock_tool_sources()
156+
assert STOCK_TOOL_SOURCES
157+
tool_version_sources = STOCK_TOOL_SOURCES.get(tool_id)
158+
if tool_version_sources is None:
159+
return None
160+
return tool_version_sources.get(tool_version)
161+
162+
163+
def _init_stock_tool_sources() -> None:
164+
global STOCK_TOOL_SOURCES
165+
if STOCK_TOOL_SOURCES is None:
166+
STOCK_TOOL_SOURCES = {}
167+
for tool_source in stock_tool_sources():
168+
tool_id = tool_source.parse_id()
169+
tool_version = tool_source.parse_version()
170+
if tool_id not in STOCK_TOOL_SOURCES:
171+
STOCK_TOOL_SOURCES[tool_id] = {}
172+
STOCK_TOOL_SOURCES[tool_id][tool_version] = tool_source

test/unit/app/tools/test_stock.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from galaxy.tools.stock import (
2+
stock_tool_paths,
3+
stock_tool_sources,
4+
)
5+
6+
7+
def test_stock_tool_paths():
8+
file_names = [f.name for f in list(stock_tool_paths())]
9+
assert "merge_collection.xml" in file_names
10+
assert "meme.xml" in file_names
11+
assert "output_auto_format.xml" in file_names
12+
13+
14+
def test_stock_tool_sources():
15+
tool_source = next(stock_tool_sources())
16+
assert tool_source.parse_id()

test/unit/tool_shed/test_tool_source.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,9 @@ def test_get_tool(provides_repositories: ProvidesRepositoriesContext, new_reposi
3030
)
3131
assert len(cached_bundle.input_models) == 3
3232

33-
print(RequestToolState.parameter_model_for(cached_bundle).model_json_schema())
33+
34+
def test_stock_bundle(provides_repositories: ProvidesRepositoriesContext):
35+
cached_bundle = tool_input_models_cached_for(
36+
provides_repositories, "__ZIP_COLLECTION__", "1.0.0", repository_clone_url=None
37+
)
38+
assert len(cached_bundle.input_models) == 2

0 commit comments

Comments
 (0)