mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-11-03 04:43:11 +08:00
Found by running: ``` make pyupgrade ruff check --fix . ruff check --preview --unsafe-fixes --select=F401 --fix . make format make update-client-api-schema ``` The bulk of the changes are replacements of typing deprecated aliases such as `Dict` and `List` with the standard library classes. These aliases became redundant in Python 3.9 when the corresponding pre-existing classes were enhanced to support `[]`, see https://docs.python.org/3/library/typing.html#deprecated-aliases Also: - Update the `pyupgrade` Makefile target to use `--py38-plus` for the packages needed by Pulsar, including the new galaxy-tool-util-models package.
192 lines
7.9 KiB
Python
192 lines
7.9 KiB
Python
import os
|
|
import tempfile
|
|
from collections import namedtuple
|
|
from typing import (
|
|
Optional,
|
|
)
|
|
|
|
from galaxy import exceptions
|
|
from galaxy.exceptions import (
|
|
InconsistentApplicationState,
|
|
InternalServerError,
|
|
ObjectNotFound,
|
|
RequestParameterInvalidException,
|
|
)
|
|
from galaxy.tool_shed.metadata.metadata_generator import RepositoryMetadataToolDict
|
|
from galaxy.tool_shed.util.basic_util import remove_dir
|
|
from galaxy.tool_shed.util.hg_util import (
|
|
clone_repository,
|
|
get_changectx_for_changeset,
|
|
)
|
|
from galaxy.tool_util.model_factory import parse_tool_custom
|
|
from galaxy.tool_util.parser import (
|
|
get_tool_source,
|
|
ToolSource,
|
|
)
|
|
from galaxy.tools.stock import stock_tool_sources
|
|
from galaxy.util import relpath
|
|
from tool_shed.context import (
|
|
ProvidesRepositoriesContext,
|
|
SessionRequestContext,
|
|
)
|
|
from tool_shed.util.common_util import generate_clone_url_for
|
|
from tool_shed.webapp.model import RepositoryMetadata
|
|
from tool_shed.webapp.search.tool_search import ToolSearch
|
|
from tool_shed_client.schema import ShedParsedTool
|
|
from .repositories import get_repository_revision_metadata_model
|
|
from .trs import trs_tool_id_to_repository_metadata
|
|
|
|
STOCK_TOOL_SOURCES: Optional[dict[str, dict[str, ToolSource]]] = None
|
|
|
|
|
|
def search(trans: SessionRequestContext, q: str, page: int = 1, page_size: int = 10) -> dict:
|
|
"""
|
|
Perform the search over TS tools index.
|
|
Note that search works over the Whoosh index which you have
|
|
to pre-create with scripts/tool_shed/build_ts_whoosh_index.sh manually.
|
|
Also TS config option toolshed_search_on has to be True and
|
|
whoosh_index_dir has to be specified.
|
|
"""
|
|
app = trans.app
|
|
conf = app.config
|
|
if not conf.toolshed_search_on:
|
|
raise exceptions.ConfigDoesNotAllowException(
|
|
"Searching the TS through the API is turned off for this instance."
|
|
)
|
|
if not conf.whoosh_index_dir:
|
|
raise exceptions.ConfigDoesNotAllowException(
|
|
"There is no directory for the search index specified. Please contact the administrator."
|
|
)
|
|
search_term = q.strip()
|
|
if len(search_term) < 1:
|
|
raise exceptions.RequestParameterInvalidException("The search term has to be at least one character long.")
|
|
|
|
tool_search = ToolSearch()
|
|
|
|
Boosts = namedtuple(
|
|
"Boosts", ["tool_name_boost", "tool_description_boost", "tool_help_boost", "tool_repo_owner_username_boost"]
|
|
)
|
|
boosts = Boosts(
|
|
float(conf.get("tool_name_boost", 1.2)),
|
|
float(conf.get("tool_description_boost", 0.6)),
|
|
float(conf.get("tool_help_boost", 0.4)),
|
|
float(conf.get("tool_repo_owner_username_boost", 0.3)),
|
|
)
|
|
|
|
results = tool_search.search(trans.app, search_term, page, page_size, boosts)
|
|
results["hostname"] = trans.repositories_hostname
|
|
return results
|
|
|
|
|
|
def get_repository_metadata_tool_dict(
|
|
trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str
|
|
) -> tuple[RepositoryMetadata, RepositoryMetadataToolDict]:
|
|
if trs_tool_id.count("~") < 2:
|
|
RequestParameterInvalidException(f"Invalid TRS tool id ({trs_tool_id})")
|
|
|
|
name, owner, tool_id = trs_tool_id.split("~", 3)
|
|
repository, metadata_by_version = trs_tool_id_to_repository_metadata(trans, trs_tool_id)
|
|
if tool_version not in metadata_by_version:
|
|
raise ObjectNotFound()
|
|
tool_version_repository_metadata: RepositoryMetadata = metadata_by_version[tool_version]
|
|
raw_metadata = tool_version_repository_metadata.metadata
|
|
tool_dicts: list[RepositoryMetadataToolDict] = raw_metadata.get("tools", [])
|
|
for tool_dict in tool_dicts:
|
|
if tool_dict["id"] != tool_id or tool_dict["version"] != tool_version:
|
|
continue
|
|
return tool_version_repository_metadata, tool_dict
|
|
raise ObjectNotFound()
|
|
|
|
|
|
def parsed_tool_model_cached_for(
|
|
trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
|
|
) -> ShedParsedTool:
|
|
model_cache = trans.app.model_cache
|
|
parsed_tool = model_cache.get_cache_entry_for(ShedParsedTool, trs_tool_id, tool_version)
|
|
if parsed_tool is not None:
|
|
return parsed_tool
|
|
parsed_tool = parsed_tool_model_for(trans, trs_tool_id, tool_version, repository_clone_url=repository_clone_url)
|
|
model_cache.insert_cache_entry_for(parsed_tool, trs_tool_id, tool_version)
|
|
return parsed_tool
|
|
|
|
|
|
def parsed_tool_model_for(
|
|
trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
|
|
) -> ShedParsedTool:
|
|
tool_source, repository_metadata = tool_source_for(
|
|
trans, trs_tool_id, tool_version, repository_clone_url=repository_clone_url
|
|
)
|
|
parsed_tool = parse_tool_custom(tool_source, ShedParsedTool)
|
|
if repository_metadata:
|
|
revision_model = get_repository_revision_metadata_model(
|
|
trans.app, repository_metadata.repository, repository_metadata, recursive=False
|
|
)
|
|
parsed_tool.repository_revision = revision_model
|
|
return parsed_tool
|
|
|
|
|
|
def tool_source_for(
|
|
trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
|
|
) -> tuple[ToolSource, Optional[RepositoryMetadata]]:
|
|
if "~" in trs_tool_id:
|
|
return _shed_tool_source_for(trans, trs_tool_id, tool_version, repository_clone_url)
|
|
else:
|
|
tool_source = _stock_tool_source_for(trs_tool_id, tool_version)
|
|
if tool_source is None:
|
|
raise ObjectNotFound()
|
|
return tool_source, None
|
|
|
|
|
|
def _shed_tool_source_for(
|
|
trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
|
|
) -> tuple[ToolSource, RepositoryMetadata]:
|
|
rval = get_repository_metadata_tool_dict(trans, trs_tool_id, tool_version)
|
|
repository_metadata, tool_version_metadata = rval
|
|
tool_config = tool_version_metadata["tool_config"]
|
|
|
|
repo = repository_metadata.repository.hg_repo
|
|
ctx = get_changectx_for_changeset(repo, repository_metadata.changeset_revision)
|
|
work_dir = tempfile.mkdtemp(prefix="tmp-toolshed-tool_source")
|
|
if repository_clone_url is None:
|
|
repository_clone_url = generate_clone_url_for(trans, repository_metadata.repository)
|
|
try:
|
|
cloned_ok, error_message = clone_repository(repository_clone_url, work_dir, str(ctx.rev()))
|
|
if error_message:
|
|
raise InternalServerError("Failed to materialize target repository revision")
|
|
repo_files_dir = repository_metadata.repository.hg_repository_path(trans.app.config.file_path)
|
|
if not repo_files_dir:
|
|
raise InconsistentApplicationState(
|
|
f"Failed to resolve repository path from hgweb_config_manager for [{trs_tool_id}], inconsistent repository state or application configuration"
|
|
)
|
|
repo_rel_tool_path = relpath(tool_config, repo_files_dir)
|
|
path_to_tool = os.path.join(work_dir, repo_rel_tool_path)
|
|
if not os.path.exists(path_to_tool):
|
|
raise InconsistentApplicationState(
|
|
f"Target tool expected at [{path_to_tool}] and not found, inconsistent repository state or application configuration"
|
|
)
|
|
tool_source = get_tool_source(path_to_tool)
|
|
return tool_source, repository_metadata
|
|
finally:
|
|
remove_dir(work_dir)
|
|
|
|
|
|
def _stock_tool_source_for(tool_id: str, tool_version: str) -> Optional[ToolSource]:
|
|
_init_stock_tool_sources()
|
|
assert STOCK_TOOL_SOURCES
|
|
tool_version_sources = STOCK_TOOL_SOURCES.get(tool_id)
|
|
if tool_version_sources is None:
|
|
return None
|
|
return tool_version_sources.get(tool_version)
|
|
|
|
|
|
def _init_stock_tool_sources() -> None:
|
|
global STOCK_TOOL_SOURCES
|
|
if STOCK_TOOL_SOURCES is None:
|
|
STOCK_TOOL_SOURCES = {}
|
|
for tool_source in stock_tool_sources():
|
|
tool_id = tool_source.parse_id()
|
|
tool_version = tool_source.parse_version()
|
|
if tool_id not in STOCK_TOOL_SOURCES:
|
|
STOCK_TOOL_SOURCES[tool_id] = {}
|
|
STOCK_TOOL_SOURCES[tool_id][tool_version] = tool_source
|