Skip to content

Commit e4afba8

Browse files
committed
Add support for -t/--tuples-only option to print rows without extra output
This commit implements a new --tuples-only option similar to psql's -t flag, which prints query results without status messages or timing information. Features: - `-t` or `--tuples-only` without value defaults to csv-noheader format - `-t <format>` allows specifying any table format (e.g., `-t minimal`) - Suppresses "SELECT X" status messages when enabled - Suppresses "Time: X.XXXs" timing output when enabled - Does not affect normal output when option is not used Implementation details: - Added `tuples_only` parameter to PGCli.__init__() - Added `tuples_only` field to OutputSettings namedtuple - Modified format_output() to skip status when tuples_only is True - Modified timing output logic to skip when tuples_only is True - Preserves all existing functionality when flag is not used Example usage: pgcli -t -c "SELECT oid FROM pg_roles WHERE rolname='user';" # Output: 2124219 (nothing else) pgcli -t minimal -c "SELECT oid, rolname FROM pg_roles LIMIT 3;" # Output: aligned columns without headers or status Made with ❤️ and 🤖 Claude Code
1 parent 1723391 commit e4afba8

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

changelog.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ Features:
99
* Support dsn specific init-command in the config file
1010
* Add suggestion when setting the search_path
1111
* Allow per dsn_alias ssh tunnel selection
12+
* Add support for `--tuples-only` (`-t`) option to print rows without extra output.
13+
* Similar to psql's `-t` flag
14+
* Command line option `-t` or `--tuples-only`
15+
* Defaults to `csv-noheader` format when used as flag
16+
* Can specify custom format: `-t minimal`, `-t tsv`, etc.
17+
* Suppresses status messages and timing information
1218

1319
Internal:
1420
---------

pgcli/main.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117

118118
OutputSettings = namedtuple(
119119
"OutputSettings",
120-
"table_format dcmlfmt floatfmt column_date_formats missingval expanded max_width case_function style_output max_field_width",
120+
"table_format dcmlfmt floatfmt column_date_formats missingval expanded max_width case_function style_output max_field_width tuples_only",
121121
)
122122
OutputSettings.__new__.__defaults__ = (
123123
None,
@@ -130,6 +130,7 @@
130130
lambda x: x,
131131
None,
132132
DEFAULT_MAX_FIELD_WIDTH,
133+
False,
133134
)
134135

135136

@@ -179,6 +180,7 @@ def __init__(
179180
application_name="pgcli",
180181
single_connection=False,
181182
less_chatty=None,
183+
tuples_only=None,
182184
prompt=None,
183185
prompt_dsn=None,
184186
auto_vertical_output=False,
@@ -235,7 +237,13 @@ def __init__(
235237

236238
self.min_num_menu_lines = c["main"].as_int("min_num_menu_lines")
237239
self.multiline_continuation_char = c["main"]["multiline_continuation_char"]
238-
self.table_format = c["main"]["table_format"]
240+
# Override table_format if tuples_only is specified
241+
if tuples_only:
242+
self.table_format = tuples_only
243+
self.tuples_only = True
244+
else:
245+
self.table_format = c["main"]["table_format"]
246+
self.tuples_only = False
239247
self.syntax_style = c["main"]["syntax_style"]
240248
self.cli_style = c["colors"]
241249
self.wider_completion_menu = c["main"].as_bool("wider_completion_menu")
@@ -850,7 +858,7 @@ def execute_command(self, text, handle_closed_connection=True):
850858
except KeyboardInterrupt:
851859
pass
852860

853-
if self.pgspecial.timing_enabled:
861+
if self.pgspecial.timing_enabled and not self.tuples_only:
854862
# Only add humanized time display if > 1 second
855863
if query.total_time > 1:
856864
print(
@@ -1135,6 +1143,7 @@ def _evaluate_command(self, text):
11351143
case_function=(self.completer.case if self.settings["case_column_headers"] else lambda x: x),
11361144
style_output=self.style_output,
11371145
max_field_width=self.max_field_width,
1146+
tuples_only=self.tuples_only,
11381147
)
11391148
execution = time() - start
11401149
formatted = format_output(title, cur, headers, status, settings, self.explain_mode)
@@ -1381,6 +1390,15 @@ def echo_via_pager(self, text, color=None):
13811390
default=False,
13821391
help="Skip intro on startup and goodbye on exit.",
13831392
)
1393+
@click.option(
1394+
"-t",
1395+
"--tuples-only",
1396+
"tuples_only",
1397+
is_flag=False,
1398+
flag_value="csv-noheader",
1399+
default=None,
1400+
help="Print rows only (default: csv-noheader). Optionally specify a format (e.g., -t minimal).",
1401+
)
13841402
@click.option("--prompt", help='Prompt format (Default: "\\u@\\h:\\d> ").')
13851403
@click.option(
13861404
"--prompt-dsn",
@@ -1444,6 +1462,7 @@ def cli(
14441462
row_limit,
14451463
application_name,
14461464
less_chatty,
1465+
tuples_only,
14471466
prompt,
14481467
prompt_dsn,
14491468
list_databases,
@@ -1506,6 +1525,7 @@ def cli(
15061525
application_name=application_name,
15071526
single_connection=single_connection,
15081527
less_chatty=less_chatty,
1528+
tuples_only=tuples_only,
15091529
prompt=prompt,
15101530
prompt_dsn=prompt_dsn,
15111531
auto_vertical_output=auto_vertical_output,
@@ -1893,8 +1913,8 @@ def format_status(cur, status):
18931913

18941914
output = itertools.chain(output, formatted)
18951915

1896-
# Only print the status if it's not None
1897-
if status:
1916+
# Only print the status if it's not None and tuples_only is not enabled
1917+
if status and not settings.tuples_only:
18981918
output = itertools.chain(output, [format_status(cur, status)])
18991919

19001920
return output

0 commit comments

Comments
 (0)