diff --git a/changelog.rst b/changelog.rst index 5a9bc17f1..d7735a69c 100644 --- a/changelog.rst +++ b/changelog.rst @@ -12,6 +12,12 @@ Bug fixes: ---------- * Fix the development setup instructions to activate the ``.venv`` directory created by ``uv venv``. +* ``--auto-vertical-output``, ``\x auto`` and ``auto_expand`` in the config work + in ``-c``/``-f`` mode. The terminal width was read from the prompt, which + those modes never build, so every statement failed with ``'NoneType' object + has no attribute 'output'``. Without a prompt the terminal is asked directly, + and only when the output is one: a pipe or a file gets the plain table, as + with psql's ``\x auto``. 4.7.1 (2026-09-20) ================== diff --git a/pgcli/main.py b/pgcli/main.py index 6ea90ab5a..7b9ff3f5b 100644 --- a/pgcli/main.py +++ b/pgcli/main.py @@ -1348,6 +1348,19 @@ def _limit_output(self, cur): return new_cur, new_status + def _output_width(self): + """Columns available to auto-expand into, or None when it must not apply. + + In -c/-f mode no prompt is ever built, so the terminal is asked + directly. psql's \\x auto only expands when the output is a terminal: + a pipe or a file gets the plain table whatever its width. + """ + if self.prompt_app: + return self.prompt_app.output.get_size().columns + if sys.stdout.isatty(): + return shutil.get_terminal_size().columns + return None + def _evaluate_command(self, text): """Used to run a command entered by the user during CLI operation (Puts the E in REPL) @@ -1390,7 +1403,7 @@ def _evaluate_command(self, text): cur, status = self._limit_output(cur) if self.pgspecial.auto_expand or self.auto_expand: - max_width = self.prompt_app.output.get_size().columns + max_width = self._output_width() else: max_width = None diff --git a/tests/test_main.py b/tests/test_main.py index a80f6ada2..badb804f9 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1140,3 +1140,29 @@ def test_connect_timeout_config_value_must_be_a_number(tmpdir): f.write("[main]\nconnect_timeout = soon\n") with pytest.raises(ValueError): PGCli(pgclirc_file=rc) + + +@dbtest +def test_auto_expand_works_without_a_prompt(executor): + # -c/-f mode never builds the prompt, and --auto-vertical-output (or + # \x auto, or auto_expand in the config) then failed every statement + # with "'NoneType' object has no attribute 'output'". Output that is not + # a terminal gets the plain table, as psql's \x auto does. + cli = PGCli(pgexecute=executor, auto_vertical_output=True) + assert cli.prompt_app is None + with mock.patch("pgcli.main.sys.stdout.isatty", return_value=False): + output, query = cli._evaluate_command("select 1 as a, 2 as b") + assert query.successful + assert not any("RECORD 1" in line for line in output) + + +@dbtest +def test_auto_expand_without_a_prompt_asks_the_terminal(executor): + cli = PGCli(pgexecute=executor, auto_vertical_output=True) + with ( + mock.patch("pgcli.main.sys.stdout.isatty", return_value=True), + mock.patch("pgcli.main.shutil.get_terminal_size", return_value=os.terminal_size((5, 24))), + ): + output, query = cli._evaluate_command("select 1 as a, 2 as b") + assert query.successful + assert any("RECORD 1" in line for line in output)