Coverage for src / sql_tool / cli / output.py: 97%

33 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-02-14 15:28 -0500

1"""Output format selection and TTY auto-detection.""" 

2 

3from __future__ import annotations 

4 

5import sys 

6from enum import StrEnum 

7from typing import TYPE_CHECKING 

8 

9if TYPE_CHECKING: 

10 from sql_tool.formatters.base import Formatter 

11 

12 

13class OutputFormat(StrEnum): 

14 TABLE = "table" 

15 JSON = "json" 

16 CSV = "csv" 

17 

18 

19def detect_tty() -> bool: 

20 return sys.stdout.isatty() 

21 

22 

23def resolve_format(format_flag: str | None) -> str: 

24 """Determine the output format. 

25 

26 Explicit --format overrides TTY detection. 

27 Default: table for TTY, csv for pipes. 

28 """ 

29 if format_flag is not None: 

30 return format_flag 

31 return "table" if detect_tty() else "csv" 

32 

33 

34def get_formatter( 

35 format_flag: str | None = None, 

36 *, 

37 compact: bool = False, 

38 width: int = 40, 

39 no_header: bool = False, 

40) -> Formatter: 

41 """Build and return the appropriate formatter instance.""" 

42 # Import here to trigger registry population from formatter modules. 

43 import sql_tool.formatters.csv # noqa: F401 

44 import sql_tool.formatters.json # noqa: F401 

45 import sql_tool.formatters.table # noqa: F401 

46 from sql_tool.formatters.base import registry 

47 

48 fmt_name = resolve_format(format_flag) 

49 

50 kwargs: dict[str, object] = {} 

51 if fmt_name == "table": 

52 kwargs["width"] = width 

53 elif fmt_name == "json": 

54 kwargs["compact"] = compact 

55 elif fmt_name == "csv": 

56 kwargs["no_header"] = no_header 

57 

58 return registry.get(fmt_name, **kwargs) 

59 

60 

61def write_output(formatter: Formatter, result: object) -> None: 

62 """Write formatted output to stdout.""" 

63 for line in formatter.format(result): # type: ignore[arg-type] 

64 sys.stdout.write(line + "\n")