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
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-14 15:28 -0500
1"""Output format selection and TTY auto-detection."""
3from __future__ import annotations
5import sys
6from enum import StrEnum
7from typing import TYPE_CHECKING
9if TYPE_CHECKING:
10 from sql_tool.formatters.base import Formatter
13class OutputFormat(StrEnum):
14 TABLE = "table"
15 JSON = "json"
16 CSV = "csv"
19def detect_tty() -> bool:
20 return sys.stdout.isatty()
23def resolve_format(format_flag: str | None) -> str:
24 """Determine the output format.
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"
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
48 fmt_name = resolve_format(format_flag)
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
58 return registry.get(fmt_name, **kwargs)
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")