Coverage for lintro / utils / config_validation.py: 88%

43 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Configuration validation functions for Lintro. 

2 

3This module provides functions for validating configuration consistency 

4across tools and checking tool injectability. 

5""" 

6 

7from __future__ import annotations 

8 

9from lintro.enums.tool_name import ToolName 

10from lintro.utils.config import load_lintro_tool_config 

11from lintro.utils.config_constants import GLOBAL_SETTINGS, ToolConfigInfo 

12from lintro.utils.config_priority import _get_nested_value, get_effective_line_length 

13from lintro.utils.native_parsers import _load_native_tool_config 

14 

15 

16def is_tool_injectable(tool_name: str | ToolName) -> bool: 

17 """Check if Lintro can inject config to a tool. 

18 

19 Args: 

20 tool_name: Name of the tool (string or ToolName enum). 

21 

22 Returns: 

23 True if Lintro can inject config via CLI or generated config file. 

24 """ 

25 injectable_set: set[ToolName] = GLOBAL_SETTINGS["line_length"]["injectable"] 

26 # ToolName is a StrEnum, so string comparison works 

27 tool_name_lower = tool_name.lower() if isinstance(tool_name, str) else tool_name 

28 return tool_name_lower in injectable_set 

29 

30 

31def validate_config_consistency() -> list[str]: 

32 """Check for inconsistencies in line length settings across tools. 

33 

34 Returns: 

35 List of warning messages about inconsistent configurations. 

36 """ 

37 warnings: list[str] = [] 

38 effective_line_length = get_effective_line_length(ToolName.RUFF) 

39 

40 if effective_line_length is None: 

41 return warnings 

42 

43 # Check each tool's native config for mismatches 

44 tools_config: dict[ToolName, str] = GLOBAL_SETTINGS["line_length"]["tools"] 

45 for tool_name, setting_key in tools_config.items(): 

46 if tool_name == ToolName.RUFF: 

47 continue # Skip Ruff (it's the source of truth) 

48 

49 native = _load_native_tool_config(tool_name) 

50 native_value = _get_nested_value(native, setting_key) 

51 

52 if native_value is not None and native_value != effective_line_length: 

53 injectable = is_tool_injectable(tool_name) 

54 if injectable: 

55 warnings.append( 

56 f"{tool_name}: Native config has {setting_key}={native_value}, " 

57 f"but Lintro will override with {effective_line_length}", 

58 ) 

59 else: 

60 warnings.append( 

61 f"Warning: {tool_name}: Native config has " 

62 f"{setting_key}={native_value}, " 

63 f"differs from central line_length={effective_line_length}. " 

64 f"Lintro cannot override this tool's native config - " 

65 f"update manually for consistency.", 

66 ) 

67 

68 return warnings 

69 

70 

71def get_tool_config_summary() -> dict[str, ToolConfigInfo]: 

72 """Get a summary of configuration for all tools. 

73 

74 Returns: 

75 Dictionary mapping tool names to their config info. 

76 """ 

77 tools = [ 

78 ToolName.RUFF, 

79 ToolName.BLACK, 

80 ToolName.YAMLLINT, 

81 ToolName.MARKDOWNLINT, 

82 ToolName.BANDIT, 

83 ToolName.HADOLINT, 

84 ToolName.ACTIONLINT, 

85 ] 

86 summary: dict[str, ToolConfigInfo] = {} 

87 

88 for tool_name in tools: 

89 info = ToolConfigInfo( 

90 tool_name=tool_name, 

91 native_config=_load_native_tool_config(tool_name), 

92 lintro_tool_config=load_lintro_tool_config(tool_name), 

93 is_injectable=is_tool_injectable(tool_name), 

94 ) 

95 

96 # Compute effective line_length 

97 effective_ll = get_effective_line_length(tool_name) 

98 if effective_ll is not None: 

99 info.effective_config["line_length"] = effective_ll 

100 

101 summary[tool_name] = info 

102 

103 # Add warnings 

104 warnings = validate_config_consistency() 

105 for warning in warnings: 

106 for tool_name in tools: 

107 if tool_name in warning.lower(): 

108 summary[tool_name].warnings.append(warning) 

109 break 

110 

111 return summary