Coverage for src/mafw/devtools/toolchain/registry.py: 100%
19 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-26 09:13 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-26 09:13 +0000
1# Copyright 2026 European Union
2# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
3# SPDX-License-Identifier: EUPL-1.2
4"""
5Central registry for ToolChainTool instances.
7The :class:`ToolRegistry` maintains an ordered collection of all registered
8development tools, enabling discovery and iteration by the CLI commands.
9Tools are stored in insertion order and can be retrieved by name or filtered
10by category.
11"""
13from __future__ import annotations
15from mafw.devtools.toolchain.base import Category, ToolChainTool
18class ToolRegistry:
19 """Central registry that maintains all registered ToolChainTool instances.
21 Tools are stored in insertion order and indexed by name for O(1) lookup.
22 Duplicate names are rejected to ensure each tool has a unique identifier
23 within the registry.
25 Usage::
27 registry = ToolRegistry()
28 registry.register(my_tool)
29 all_tools = registry.all()
30 project_tools = registry.filter_by_category('project')
31 specific = registry.get('ruff')
32 """
34 def __init__(self) -> None:
35 # Ordered list preserving insertion order (Requirement 19.1).
36 self._tools: list[ToolChainTool] = []
37 # Name-indexed lookup for O(1) retrieval and duplicate detection.
38 self._by_name: dict[str, ToolChainTool] = {}
40 def register(self, tool: ToolChainTool) -> None:
41 """Add a tool to the registry.
43 The tool is appended to the internal list and indexed by name.
44 If a tool with the same name already exists, a :exc:`ValueError`
45 is raised and the registry state remains unchanged.
47 :param tool: The tool instance to register.
48 :raises ValueError: If a tool with the same name is already
49 registered.
50 """
51 if tool.name in self._by_name:
52 raise ValueError(f'Duplicate tool name: {tool.name!r}')
53 self._tools.append(tool)
54 self._by_name[tool.name] = tool
56 def all(self) -> list[ToolChainTool]:
57 """Return all registered tools in insertion order.
59 :return: A new list containing all tools in the order they were
60 registered.
61 :rtype: list[toolchain.ToolChainTool]
62 """
63 return list(self._tools)
65 def filter_by_category(self, category: Category) -> list[ToolChainTool]:
66 """Return tools matching the given category, preserving insertion order.
68 :param category: The category to filter by (``"host"`` or ``"project"``).
69 :return: A list of matching tools, or an empty list if none match.
70 :rtype: list[toolchain.ToolChainTool]
71 """
72 return [t for t in self._tools if t.category == category]
74 def get(self, name: str) -> ToolChainTool:
75 """Retrieve a tool by its exact name (case-sensitive).
77 :param name: The tool name to look up.
78 :return: The matching :class:`.toolchain.ToolChainTool` instance.
79 :rtype: toolchain.ToolChainTool
80 :raises KeyError: If no tool with the given name is registered.
81 """
82 if name not in self._by_name:
83 raise KeyError(f'Tool not found: {name!r}')
84 return self._by_name[name]