LazyTool: answer get_panel_section off the entry (no materialise)

AgentTools.get_tool_categories iterates toolbox.tools() and reads
tool.get_panel_section()[1] on every visible tool. get_panel_section was
not on the LazyTool stub surface, so under the permissive default that
sweep materialised the entire toolbox to build the category list (and
under LAZY_TOOL_STRICT=1 it would now raise).

The populator already stamps panel_section_id / panel_section_name onto
ToolIndexEntry, so forward the call off the entry — matching the
(section_id, section_name) / (None, None) contract of
Tool.get_panel_section — and keep the walk lazy.

Claude-Session: https://claude.ai/code/session_018L7ZmCv2ubKA3JNeSL8Pkr
This commit is contained in:
mvdbeek
2026-07-28 17:27:26 +02:00
parent bcd8690a2f
commit ba1a3b9f69
2 changed files with 26 additions and 0 deletions
+16
View File
@@ -252,6 +252,22 @@ class LazyTool:
def lineage(self):
return self._lineage
def get_panel_section(self) -> tuple[str, str] | tuple[None, None]:
"""Answer the tool's ``(section_id, section_name)`` off the entry.
``Tool.get_panel_section`` resolves this through
``toolbox.get_section_for_tool`` (a panel lookup), but the populator
already stamps the placement onto ``ToolIndexEntry``. Full-toolbox
sweeps read this — e.g. ``AgentTools.get_tool_categories`` iterates
``toolbox.tools()`` and reads ``get_panel_section()[1]`` per tool —
so forwarding off the entry keeps that O(N) walk from materialising
every tool.
"""
entry = self._entry
if entry.panel_section_id:
return (entry.panel_section_id, entry.panel_section_name or "")
return (None, None)
@property
def version_object(self):
# Mirror ``Tool.version_object`` (lib/galaxy/tools/__init__.py:1213).
+10
View File
@@ -155,6 +155,16 @@ def test_to_panel_entry_carries_client_contract_fields():
assert "config_file" not in d
def test_get_panel_section_answered_off_entry_without_materialise():
# AgentTools.get_tool_categories sweeps the whole toolbox and reads
# get_panel_section()[1] per tool; forwarding off the entry keeps that
# walk from parsing every tool. _stub's default materialize raises.
e = _entry(panel_section_id="ngs", panel_section_name="NGS: Mapping")
assert _stub(e).get_panel_section() == ("ngs", "NGS: Mapping")
# No section stamped -> (None, None), matching Tool.get_panel_section.
assert _stub(_entry()).get_panel_section() == (None, None)
def test_to_dict_materialises():
calls: list[Any] = []