diff --git a/changelog.rst b/changelog.rst index fdfcde538..6a92b5bec 100644 --- a/changelog.rst +++ b/changelog.rst @@ -4,6 +4,10 @@ Upcoming (TBD) Features: --------- * Add support for `\\T` prompt escape sequence to display transaction status (similar to psql's `%x`). +* Add ``-t``/``--tuples-only`` CLI option to set table format at startup. + * Sets table format to ``csv-noheader`` (rows only, no headers) + * CLI shortcut equivalent to ``\T csv-noheader`` + * Does not suppress timing or status messages (use ``\pset`` for that) 4.4.0 (2025-12-24) ================== diff --git a/pgcli/main.py b/pgcli/main.py index 913228b33..56fe83fb8 100644 --- a/pgcli/main.py +++ b/pgcli/main.py @@ -179,6 +179,7 @@ def __init__( application_name="pgcli", single_connection=False, less_chatty=None, + tuples_only=None, prompt=None, prompt_dsn=None, auto_vertical_output=False, @@ -236,7 +237,10 @@ def __init__( self.min_num_menu_lines = c["main"].as_int("min_num_menu_lines") self.multiline_continuation_char = c["main"]["multiline_continuation_char"] - self.table_format = c["main"]["table_format"] + if tuples_only: + self.table_format = "csv-noheader" + else: + self.table_format = c["main"]["table_format"] self.syntax_style = c["main"]["syntax_style"] self.cli_style = c["colors"] self.wider_completion_menu = c["main"].as_bool("wider_completion_menu") @@ -1430,6 +1434,14 @@ def echo_via_pager(self, text, color=None): default=False, help="Skip intro on startup and goodbye on exit.", ) +@click.option( + "-t", + "--tuples-only", + "tuples_only", + is_flag=True, + default=False, + help="Print rows only, using csv-noheader format. Same as \\T csv-noheader.", +) @click.option("--prompt", help='Prompt format (Default: "\\u@\\h:\\d> ").') @click.option( "--prompt-dsn", @@ -1493,6 +1505,7 @@ def cli( row_limit, application_name, less_chatty, + tuples_only, prompt, prompt_dsn, list_databases, @@ -1555,6 +1568,7 @@ def cli( application_name=application_name, single_connection=single_connection, less_chatty=less_chatty, + tuples_only=tuples_only, prompt=prompt, prompt_dsn=prompt_dsn, auto_vertical_output=auto_vertical_output, diff --git a/tests/test_tuples_only.py b/tests/test_tuples_only.py new file mode 100644 index 000000000..24e6bfd32 --- /dev/null +++ b/tests/test_tuples_only.py @@ -0,0 +1,44 @@ +from unittest.mock import patch + +from click.testing import CliRunner + +from pgcli.main import cli, PGCli + + +def test_tuples_only_flag_passed_to_pgcli(): + """Test that -t passes tuples_only=True to PGCli.""" + runner = CliRunner() + with patch.object(PGCli, "__init__", autospec=True, return_value=None) as mock_pgcli: + runner.invoke(cli, ["-t", "mydb"]) + call_kwargs = mock_pgcli.call_args[1] + assert call_kwargs["tuples_only"] is True + + +def test_tuples_only_long_form(): + """Test that --tuples-only passes tuples_only=True to PGCli.""" + runner = CliRunner() + with patch.object(PGCli, "__init__", autospec=True, return_value=None) as mock_pgcli: + runner.invoke(cli, ["--tuples-only", "mydb"]) + call_kwargs = mock_pgcli.call_args[1] + assert call_kwargs["tuples_only"] is True + + +def test_tuples_only_not_set_by_default(): + """Test that tuples_only is False when -t is not used.""" + runner = CliRunner() + with patch.object(PGCli, "__init__", autospec=True, return_value=None) as mock_pgcli: + runner.invoke(cli, ["mydb"]) + call_kwargs = mock_pgcli.call_args[1] + assert call_kwargs["tuples_only"] is False + + +def test_tuples_only_sets_csv_noheader_format(): + """Test that tuples_only=True sets table_format to csv-noheader.""" + pgcli = PGCli(tuples_only=True) + assert pgcli.table_format == "csv-noheader" + + +def test_default_table_format_without_tuples_only(): + """Test that table_format uses config default when tuples_only is False.""" + pgcli = PGCli() + assert pgcli.table_format != "csv-noheader" # Uses config default