Coverage for src/mafw/devtools/toolchain/filtering.py: 100%

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

5Tool filtering utility for the toolchain command group. 

6 

7This module provides :func:`resolve_tools`, a shared function used by all CLI 

8subcommands to determine which tools to process based on the ``--include-host``, 

9``-i``/``--include``, and ``-e``/``--exclude`` options. It enforces mutual 

10exclusivity between include and exclude filters, warns on unrecognized tool 

11names, and preserves the original registration order from the registry. 

12""" 

13 

14from __future__ import annotations 

15 

16import warnings 

17 

18from mafw.devtools import DevtoolsError 

19from mafw.devtools.toolchain.base import ToolChainTool 

20from mafw.devtools.toolchain.registry import ToolRegistry 

21 

22 

23def resolve_tools( 

24 registry: ToolRegistry, 

25 *, 

26 include: tuple[str, ...] = (), 

27 exclude: tuple[str, ...] = (), 

28 include_host: bool = False, 

29) -> list[ToolChainTool]: 

30 """Filter the registry based on CLI options. 

31 

32 The filtering pipeline proceeds in order: 

33 

34 1. Reject mutually exclusive ``include`` and ``exclude`` arguments. 

35 2. Start with all tools from the registry (preserving insertion order). 

36 3. If *include_host* is ``False``, remove tools with category ``"host"``. 

37 4. If *include* is non-empty, keep only tools whose name is in the set 

38 (emit a warning for each unrecognized name). 

39 5. If *exclude* is non-empty, remove tools whose name is in the set 

40 (emit a warning for each unrecognized name). 

41 

42 :param registry: The central tool registry to query. 

43 :param include: Tool names to include exclusively. Only tools whose 

44 ``name`` matches one of these values will be returned. 

45 :param exclude: Tool names to exclude. Tools whose ``name`` matches one 

46 of these values will be removed from the result. 

47 :param include_host: When ``False`` (the default), tools with 

48 ``category="host"`` are excluded before any name-based filtering. 

49 :return: A list of tools in their original registration order. 

50 :raises DevtoolsError: If both *include* and *exclude* are non-empty 

51 (mutual exclusivity violation). 

52 """ 

53 # Step 1: Enforce mutual exclusivity of include and exclude. 

54 if include and exclude: 

55 raise DevtoolsError('--include and --exclude are mutually exclusive; specify one or the other, not both.') 

56 

57 # Step 2: Start with all registered tools. 

58 tools = registry.all() 

59 

60 # Step 3: Filter out host tools unless explicitly included. 

61 if not include_host: 

62 tools = [t for t in tools if t.category != 'host'] 

63 

64 # Step 4: Apply include filter (keep only named tools). 

65 if include: 

66 include_set = set(include) 

67 # Gather the set of known tool names from the current (possibly host-filtered) list. 

68 known_names = {t.name for t in tools} 

69 for name in include_set: 

70 if name not in known_names: 

71 warnings.warn( 

72 f'Unrecognized tool name in --include: {name!r}', 

73 stacklevel=2, 

74 ) 

75 tools = [t for t in tools if t.name in include_set] 

76 

77 # Step 5: Apply exclude filter (remove named tools). 

78 if exclude: 

79 exclude_set = set(exclude) 

80 # Gather the set of known tool names from the current (possibly host-filtered) list. 

81 known_names = {t.name for t in tools} 

82 for name in exclude_set: 

83 if name not in known_names: 

84 warnings.warn( 

85 f'Unrecognized tool name in --exclude: {name!r}', 

86 stacklevel=2, 

87 ) 

88 tools = [t for t in tools if t.name not in exclude_set] 

89 

90 return tools