Coverage for lintro / parsers / yamllint / yamllint_parser.py: 76%

37 statements  

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

1"""Parser for yamllint output.""" 

2 

3import re 

4 

5from loguru import logger 

6 

7from lintro.enums.severity_level import normalize_severity_level 

8from lintro.parsers.base_parser import strip_ansi_codes 

9from lintro.parsers.yamllint.yamllint_issue import YamllintIssue 

10 

11# Pattern for yamllint parsable format: "filename:line:column: [level] message (rule)" 

12_YAMLLINT_PATTERN: re.Pattern[str] = re.compile( 

13 r"^([^:]+):(\d+):(\d+):\s*\[(error|warning)\]\s+(.+?)(?:\s+\(([^)]+)\))?$", 

14) 

15 

16 

17def parse_yamllint_output(output: str) -> list[YamllintIssue]: 

18 """Parse yamllint output into a list of YamllintIssue objects. 

19 

20 Yamllint outputs in parsable format as: 

21 filename:line:column: [level] message (rule) 

22 

23 Example outputs: 

24 test_samples/yaml_violations.yml:3:1: [warning] missing document start 

25 "---" (document-start) 

26 test_samples/yaml_violations.yml:6:32: [error] trailing spaces 

27 (trailing-spaces) 

28 test_samples/yaml_violations.yml:11:81: [error] line too long (149 > 80 

29 characters) (line-length) 

30 

31 Args: 

32 output: The raw output from yamllint 

33 

34 Returns: 

35 List of YamllintIssue objects 

36 """ 

37 issues: list[YamllintIssue] = [] 

38 

39 # Skip empty output 

40 if not output.strip(): 

41 return issues 

42 

43 # Strip ANSI codes for consistent parsing across environments 

44 output = strip_ansi_codes(output) 

45 

46 lines: list[str] = output.splitlines() 

47 

48 for line in lines: 

49 line = line.strip() 

50 if not line: 

51 continue 

52 

53 match: re.Match[str] | None = _YAMLLINT_PATTERN.match(line) 

54 if match: 

55 try: 

56 filename: str 

57 line_num: str 

58 column: str 

59 level: str 

60 message: str 

61 rule: str | None 

62 filename, line_num, column, level, message, rule = match.groups() 

63 

64 # Validate and convert line number 

65 try: 

66 line_int = int(line_num) 

67 except ValueError: 

68 logger.debug(f"Invalid line number in yamllint output: {line_num}") 

69 continue 

70 

71 # Validate and convert column number 

72 column_int: int = 0 

73 if column: 

74 try: 

75 column_int = int(column) 

76 except ValueError: 

77 logger.debug( 

78 f"Invalid column number in yamllint output: {column}", 

79 ) 

80 column_int = 0 

81 

82 issues.append( 

83 YamllintIssue( 

84 file=filename, 

85 line=line_int, 

86 column=column_int, 

87 level=normalize_severity_level(level), 

88 rule=rule, 

89 message=message.strip(), 

90 ), 

91 ) 

92 except (ValueError, TypeError, IndexError) as e: 

93 logger.debug(f"Failed to parse yamllint line '{line}': {e}") 

94 continue 

95 

96 return issues