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

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. 

6 

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""" 

12 

13from __future__ import annotations 

14 

15from mafw.devtools.toolchain.base import Category, ToolChainTool 

16 

17 

18class ToolRegistry: 

19 """Central registry that maintains all registered ToolChainTool instances. 

20 

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. 

24 

25 Usage:: 

26 

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 """ 

33 

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] = {} 

39 

40 def register(self, tool: ToolChainTool) -> None: 

41 """Add a tool to the registry. 

42 

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. 

46 

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 

55 

56 def all(self) -> list[ToolChainTool]: 

57 """Return all registered tools in insertion order. 

58 

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) 

64 

65 def filter_by_category(self, category: Category) -> list[ToolChainTool]: 

66 """Return tools matching the given category, preserving insertion order. 

67 

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] 

73 

74 def get(self, name: str) -> ToolChainTool: 

75 """Retrieve a tool by its exact name (case-sensitive). 

76 

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]