Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Features:
Uses prompt_toolkit's ``ModalCursorShapeConfig``.
* Add support of Python 3.14.
* Drop support of Python 3.9.
* 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)

Bug fixes:
----------
Expand Down
16 changes: 15 additions & 1 deletion pgcli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"
Comment on lines +242 to +243

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor tuples-only by suppressing extra output

When -t/--tuples-only is used, this branch only switches the formatter to csv-noheader; the output path still appends command status in format_output (pgcli/main.py:1968-1970) and prints timing whenever enabled (pgcli/main.py:901, with the default config setting timing = True). PostgreSQL documents --tuples-only as turning off column names and row-count footers, so with the default config a query still emits SELECT n and Time: ..., which breaks users relying on this option for rows-only output. Please carry the tuples-only state through to suppress status/timing, or avoid exposing it as psql-style tuples-only.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @codex, fair point on the psql semantics. This is intentional for this PR: -t was deliberately narrowed during review to be a startup shortcut for the output format only (like a CLI \T), not psql's full tuples-only. Suppressing the status footer and timing is kept to separate, composable flags (--no-timings / --no-status) rather than bundled into -t, so each concern stays granular. So the scope here is "format shortcut", and rows-only-with-no-footers is achieved by combining flags. Open to revisiting the naming if -t/--tuples-only reads as too psql-flavored for that scope.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DiegoDAF Sigh. I know this is what I requested here, but I had a change of heart. Let's go back to aligning -t behavior with psql, to make it easier and less surprising for users coming from psql, and add back headers / timings suppression. Sorry about the back and forth.

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")
Expand Down Expand Up @@ -1439,6 +1443,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",
Expand Down Expand Up @@ -1502,6 +1514,7 @@ def cli(
row_limit,
application_name,
less_chatty,
tuples_only,
prompt,
prompt_dsn,
list_databases,
Expand Down Expand Up @@ -1564,6 +1577,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,
Expand Down
44 changes: 44 additions & 0 deletions tests/test_tuples_only.py
Original file line number Diff line number Diff line change
@@ -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