mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-21 05:45:37 +08:00
Hoist lazy-branch local imports to module level
The only local import left is lazy_toolbox's send_control_task, which is a genuine cycle: galaxy.queue_worker imports LazyToolBox at module level. Everything else - app boot, queue_worker, tool_panel_manager, services/tools, search, populator, benchmarks, uses_shed and the test modules - now imports at the top; the claimed app/tools circularity never existed (galaxy.app already imports galaxy.tools). Claude-Session: https://claude.ai/code/session_018L7ZmCv2ubKA3JNeSL8Pkr
This commit is contained in:
@@ -176,10 +176,15 @@ from galaxy.tools.data import ToolDataTableManager
|
||||
from galaxy.tools.data_manager.manager import DataManagers
|
||||
from galaxy.tools.error_reports import ErrorReports
|
||||
from galaxy.tools.evaluation import ToolTemplatingException
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
from galaxy.tools.search import (
|
||||
LazyToolboxSearch,
|
||||
ToolBoxSearch,
|
||||
)
|
||||
from galaxy.tools.source_store import (
|
||||
build_tool_source_store,
|
||||
ToolSourceStore,
|
||||
)
|
||||
from galaxy.tools.special_tools import load_lib_tools
|
||||
from galaxy.tours import (
|
||||
build_tours_registry,
|
||||
@@ -425,12 +430,6 @@ class MinimalGalaxyApplication(BasicSharedApp, HaltableContainer, SentryClientMi
|
||||
from ``build_tool_source_store`` — we let it propagate so the
|
||||
operator sees the failure at startup.
|
||||
"""
|
||||
# Local import: avoids a circular import between galaxy.app and galaxy.tools.
|
||||
from galaxy.tools.source_store import (
|
||||
build_tool_source_store,
|
||||
ToolSourceStore,
|
||||
)
|
||||
|
||||
self.tool_source_store: ToolSourceStore | None = None
|
||||
if not self.config.use_lazy_toolbox:
|
||||
return
|
||||
@@ -459,14 +458,11 @@ class MinimalGalaxyApplication(BasicSharedApp, HaltableContainer, SentryClientMi
|
||||
|
||||
def _shutdown_lazy_toolbox(self) -> None:
|
||||
toolbox = getattr(self, "_toolbox", None)
|
||||
# Lazy import: only relevant when the lazy path is in use.
|
||||
try:
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
|
||||
if isinstance(toolbox, LazyToolBox):
|
||||
if isinstance(toolbox, LazyToolBox):
|
||||
try:
|
||||
toolbox.close()
|
||||
except Exception as e:
|
||||
log.debug(f"_shutdown_lazy_toolbox: {e}")
|
||||
except Exception as e:
|
||||
log.debug(f"_shutdown_lazy_toolbox: {e}")
|
||||
|
||||
def _use_lazy_toolbox(self) -> bool:
|
||||
"""Determine whether to use LazyToolBox instead of regular ToolBox.
|
||||
@@ -482,9 +478,6 @@ class MinimalGalaxyApplication(BasicSharedApp, HaltableContainer, SentryClientMi
|
||||
|
||||
def _create_lazy_toolbox(self) -> "tools.ToolBox":
|
||||
"""Create a LazyToolBox instance."""
|
||||
# Lazy import: avoids circular import between galaxy.app and galaxy.tools.
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
|
||||
cache_size = self.config.lazy_toolbox_cache_size
|
||||
log.info(f"Using LazyToolBox with cache_size={cache_size}")
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ from galaxy.managers.sse import (
|
||||
from galaxy.model import User
|
||||
from galaxy.tools import ToolBox
|
||||
from galaxy.tools.data_manager.manager import DataManagers
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
from galaxy.tools.special_tools import load_lib_tools
|
||||
|
||||
logging.getLogger("kombu").setLevel(logging.WARNING)
|
||||
@@ -290,9 +291,6 @@ def _get_new_toolbox(app: "UniverseApplication", save_integrated_tool_panel: boo
|
||||
|
||||
new_toolbox: ToolBox
|
||||
if getattr(app.config, "use_lazy_toolbox", False) and getattr(app, "tool_source_store", None) is not None:
|
||||
# Lazy import: avoids circular import between galaxy.queue_worker and galaxy.tools.
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
|
||||
new_toolbox = LazyToolBox(
|
||||
config_filenames=tool_configs,
|
||||
tool_root_dir=app.config.tool_path,
|
||||
@@ -399,8 +397,6 @@ def reload_tool_source_cache(app, **kwargs):
|
||||
This is typically triggered by an external process (like populate_store.py --watch)
|
||||
when tool files change on disk.
|
||||
"""
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
|
||||
log.debug("Executing tool source cache reload on '%s'", app.config.server_name)
|
||||
|
||||
# Invalidate the lazy toolbox cache if the active toolbox is a LazyToolBox.
|
||||
|
||||
@@ -11,6 +11,8 @@ from galaxy.tool_shed.galaxy_install.client import InstallationTarget
|
||||
from galaxy.tool_shed.util.basic_util import strip_path
|
||||
from galaxy.tool_shed.util.repository_util import get_repository_owner
|
||||
from galaxy.tool_shed.util.shed_util_common import get_tool_panel_config_tool_path_install_dir
|
||||
from galaxy.tool_util.toolbox.base import resolve_tool_path
|
||||
from galaxy.tools.source_store.populator import populate_for_paths
|
||||
from galaxy.util import (
|
||||
Element,
|
||||
parse_xml_string,
|
||||
@@ -31,14 +33,9 @@ def _collect_new_tool_paths(elem_list, tool_path: str, shed_tool_conf: str) -> d
|
||||
— either top-level ``<tool>`` elements or ``<section>`` elements with
|
||||
nested ``<tool>`` children. Paths must match what
|
||||
``galaxy.tools.source_store.discover.discover_tools`` yields for the
|
||||
rewritten conf byte-for-byte (the partial populate filters on the string):
|
||||
a relative ``tool_path`` resolves against the conf file's directory, not
|
||||
the process cwd, so route through the same ``resolve_tool_path``.
|
||||
rewritten conf byte-for-byte (the partial populate filters on the string),
|
||||
so route through the same ``resolve_tool_path`` discover uses.
|
||||
"""
|
||||
# Local import: keeps galaxy.tools.source_store out of the eager
|
||||
# tool-shed install path's module graph.
|
||||
from galaxy.tools.source_store.discover import resolve_tool_path
|
||||
|
||||
resolved_base = resolve_tool_path(tool_path, shed_tool_conf)
|
||||
path_guids: dict[str, str | None] = {}
|
||||
|
||||
@@ -178,8 +175,6 @@ class ToolPanelManager:
|
||||
load_elem_list, tool_path, shed_tool_conf_dict["config_filename"]
|
||||
)
|
||||
if new_path_guids:
|
||||
from galaxy.tools.source_store.populator import populate_for_paths
|
||||
|
||||
populate_for_paths(
|
||||
self.app.config,
|
||||
paths=list(new_path_guids),
|
||||
|
||||
@@ -1323,6 +1323,8 @@ class LazyToolBox(ToolBox):
|
||||
# broadcasts an invalidation; removals must broadcast too or
|
||||
# peer web workers keep serving the uninstalled tool until an
|
||||
# unrelated populate happens to run.
|
||||
# Local import: genuine circularity — galaxy.queue_worker
|
||||
# imports LazyToolBox at module level.
|
||||
from galaxy.queue_worker import send_control_task
|
||||
|
||||
try:
|
||||
|
||||
@@ -57,6 +57,14 @@ from whoosh.scoring import (
|
||||
from whoosh.writing import AsyncWriter
|
||||
|
||||
from galaxy.config import GalaxyAppConfiguration
|
||||
from galaxy.tools.source_store.populator import (
|
||||
DEFAULT_STORE_NAME,
|
||||
whoosh_dir_for_store,
|
||||
)
|
||||
from galaxy.tools.source_store.search import (
|
||||
ToolSearchTuning,
|
||||
ToolWhooshIndex,
|
||||
)
|
||||
from galaxy.util import (
|
||||
ExecutionTimer,
|
||||
unicodify,
|
||||
@@ -156,16 +164,6 @@ class LazyToolboxSearch(ToolBoxSearch):
|
||||
self.index_count += 1
|
||||
|
||||
def search(self, q: str, panel_view: str, config: GalaxyAppConfiguration) -> list[str]:
|
||||
# Lazy import: avoids pulling populator's deps into module load.
|
||||
from galaxy.tools.source_store.populator import (
|
||||
DEFAULT_STORE_NAME,
|
||||
whoosh_dir_for_store,
|
||||
)
|
||||
from galaxy.tools.source_store.search import (
|
||||
ToolSearchTuning,
|
||||
ToolWhooshIndex,
|
||||
)
|
||||
|
||||
if not config.tool_search_index_dir:
|
||||
# No index dir means whoosh search is off entirely.
|
||||
return []
|
||||
|
||||
@@ -12,6 +12,7 @@ from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from galaxy.tool_util.parser.factory import TOOL_SOURCE_FACTORIES
|
||||
from .index import (
|
||||
ToolIndex,
|
||||
ToolIndexEntry,
|
||||
@@ -162,12 +163,6 @@ class ToolSourceBenchmarks:
|
||||
print("No tools found for XML parsing benchmark")
|
||||
return None
|
||||
|
||||
try:
|
||||
from galaxy.tool_util.parser.factory import TOOL_SOURCE_FACTORIES
|
||||
except ImportError:
|
||||
print("Could not import TOOL_SOURCE_FACTORIES")
|
||||
return None
|
||||
|
||||
# Use a representative tool
|
||||
path, content = tools[0]
|
||||
factory = TOOL_SOURCE_FACTORIES.get("XmlToolSource")
|
||||
@@ -188,12 +183,6 @@ class ToolSourceBenchmarks:
|
||||
print("No tools found for deserialization benchmark")
|
||||
return None
|
||||
|
||||
try:
|
||||
from galaxy.tool_util.parser.factory import TOOL_SOURCE_FACTORIES
|
||||
except ImportError:
|
||||
print("Could not import TOOL_SOURCE_FACTORIES")
|
||||
return None
|
||||
|
||||
path, content = tools[0]
|
||||
|
||||
# Simulate DB storage format
|
||||
|
||||
@@ -8,7 +8,6 @@ from typing import (
|
||||
cast,
|
||||
get_args,
|
||||
Optional,
|
||||
TYPE_CHECKING,
|
||||
)
|
||||
from uuid import UUID
|
||||
|
||||
@@ -62,14 +61,12 @@ from galaxy.tool_util_models.parameters import (
|
||||
)
|
||||
from galaxy.tools import Tool
|
||||
from galaxy.tools._types import InputFormatT
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
from galaxy.tools.search import ToolBoxSearch
|
||||
from galaxy.util.path import safe_contains
|
||||
from galaxy.webapps.galaxy.services._fetch_util import validate_and_normalize_targets
|
||||
from galaxy.webapps.galaxy.services.base import ServiceBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
ToolRunPayload = dict[str, Any]
|
||||
@@ -563,8 +560,6 @@ class ToolsService(ServiceBase):
|
||||
|
||||
def _get_lazy_toolbox(self, trans: ProvidesUserContext) -> Optional["LazyToolBox"]:
|
||||
"""Return the active toolbox if it's a LazyToolBox, else None."""
|
||||
from galaxy.tools.lazy_toolbox import LazyToolBox
|
||||
|
||||
toolbox = trans.app.toolbox
|
||||
return toolbox if isinstance(toolbox, LazyToolBox) else None
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ from unittest import SkipTest
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
from galaxy.app import UniverseApplication
|
||||
from galaxy.tools.source_store.populator import reconcile_index
|
||||
from galaxy.util.tool_shed.tool_shed_registry import DEFAULT_TOOL_SHED_URL
|
||||
from galaxy.util.unittest_utils import is_site_up
|
||||
from galaxy_test.base.populators import DEFAULT_TIMEOUT
|
||||
@@ -90,8 +91,6 @@ class UsesShed(UsesShedApi):
|
||||
# would otherwise survive the ``reload_toolbox`` below: ``LazyToolBox``
|
||||
# only re-runs the populator when discovery turns up a *new* path.
|
||||
try:
|
||||
from galaxy.tools.source_store.populator import reconcile_index
|
||||
|
||||
reconcile_index(self._app.config, rebuild_whoosh=True)
|
||||
except Exception as e:
|
||||
log.warning("reset_shed_tools: reconcile_index raised (continuing): %s", e)
|
||||
|
||||
Reference in New Issue
Block a user