Coverage for lintro / formatters / styles / grid.py: 89%

27 statements  

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

1"""Grid output style implementation.""" 

2 

3from typing import Any 

4 

5from lintro.formatters.core.format_registry import OutputStyle 

6 

7# Try to import tabulate 

8try: 

9 from tabulate import tabulate 

10 

11 TABULATE_AVAILABLE = True 

12except ImportError: 

13 TABULATE_AVAILABLE = False 

14 

15 

16class GridStyle(OutputStyle): 

17 """Output format that renders data as a formatted grid table. 

18 

19 This style creates a nicely formatted table with proper column alignment 

20 and borders, similar to what you might see in a terminal or console. 

21 """ 

22 

23 def format( 

24 self, 

25 columns: list[str], 

26 rows: list[list[Any]], 

27 tool_name: str | None = None, 

28 **kwargs: Any, 

29 ) -> str: 

30 """Format a table given columns and rows as a grid. 

31 

32 Args: 

33 columns: List of column header names. 

34 rows: List of row values (each row is a list of cell values). 

35 tool_name: Optional tool name to include in context. 

36 **kwargs: Extra options ignored by this formatter. 

37 

38 Returns: 

39 Formatted data as grid table string. 

40 """ 

41 if not rows: 

42 return "" 

43 

44 # Use tabulate if available 

45 if TABULATE_AVAILABLE: 

46 # Provide sane defaults for alignment and column widths to avoid 

47 # terminal wrapping that misaligns the grid. We keep most columns 

48 # left-aligned, numeric columns right-aligned, and cap wide 

49 # columns like File/Message. 

50 colalign_map = { 

51 "Line": "right", 

52 "Column": "right", 

53 "Fixable": "center", 

54 } 

55 colalign = [colalign_map.get(col, "left") for col in columns] 

56 

57 # Cap very wide columns so tabulate wraps within cells, preserving 

58 # alignment instead of letting the terminal wrap mid-grid. 

59 width_map: dict[str, int] = { 

60 "File": 48, 

61 "Message": 64, 

62 "Code": 12, 

63 "Line": 8, 

64 "Column": 8, 

65 "Fixable": 8, 

66 "Docs": 52, 

67 } 

68 maxcolwidths = [width_map.get(col) for col in columns] 

69 

70 return tabulate( 

71 tabular_data=rows, 

72 headers=columns, 

73 tablefmt="grid", 

74 stralign="left", 

75 numalign="right", 

76 colalign=colalign, 

77 maxcolwidths=maxcolwidths, 

78 disable_numparse=True, 

79 ) 

80 

81 # Fallback to simple format when tabulate is not available 

82 if not columns: 

83 return "" 

84 

85 # Build the header 

86 header = " | ".join(columns) 

87 separator = "-" * len(header) 

88 

89 # Build the rows 

90 formatted_rows = [] 

91 for row in rows: 

92 # Ensure row has same number of elements as columns 

93 padded_row = row + [""] * (len(columns) - len(row)) 

94 formatted_rows.append(" | ".join(str(cell) for cell in padded_row)) 

95 

96 # Combine all parts 

97 result = [header, separator] + formatted_rows 

98 return "\n".join(result)