Skip to content

with_annotated --help bypasses app.stdout and output redirection #1776

Open

Description

@AryanRG

@with_annotated command help goes to process sys.stdout instead of the application's
configured output stream. greet --help > help.txt creates/truncates the file but leaves it
empty, so embedding applications cannot capture help and users cannot export it normally.

Environment

  • cmd2 source: current main, commit 93cfe811c6a56015e3f0aec8d8e61c56faf9573c
    (editable distribution metadata: 4.3.1.dev3+g93cfe811c).
  • CPython 3.13.12; macOS 27.0, build 26A428.
  • rich 15.0.0; rich-argparse 1.8.0; prompt-toolkit 3.0.53.

Reproduction

Run this against the source revision above:

import contextlib
import io
import pathlib
import tempfile
import cmd2

class App(cmd2.Cmd):
    @cmd2.with_annotated
    def do_greet(self, name: str) -> None:
        self.poutput(name)

app_output = io.StringIO()
terminal_output = io.StringIO()
with contextlib.redirect_stdout(terminal_output):
    app = App(stdout=app_output, auto_load_commands=False)
    app.onecmd_plus_hooks('greet --help')
    with tempfile.TemporaryDirectory() as directory:
        path = pathlib.Path(directory) / 'help.txt'
        app.onecmd_plus_hooks(f'greet --help > "{path}"')
        file_output = path.read_text()
print('app output contains help:', 'Usage: greet' in app_output.getvalue())
print('redirected file contains help:', 'Usage: greet' in file_output)
print('process stdout contains help:', 'Usage: greet' in terminal_output.getvalue())
assert 'Usage: greet' in file_output, 'BUG: redirected --help is lost; help file is empty'

Observed on unchanged source: False, False, True, followed by
AssertionError: BUG: redirected --help is lost; help file is empty.
Both the app stream and redirected file are empty.

Expected: True, True, False, with help delivered to app.stdout or the requested file
and the assertion passing. Append redirection (>>) should append the help as well.

Local validation and proposed work

An unpublished local regression matrix covers five command forms (ordinary parsing,
with_unknown_args=True, base commands and nested subcommands) with app output, > and >>.
Running the same tests against unchanged production source and the local prototype gives:

pytest tests/test_annotated.py -k test_help_respects_output_destination --no-cov -n 0
unchanged source + added tests: 15 failed, 672 deselected
local prototype + same tests:  15 passed, 672 deselected

The standalone reproduction also fails on unchanged source and passes with that prototype.
These are local macOS/Python results; hosted CI and other platforms have not been exercised.

The annotated wrapper appears to omit the parser's output_to(app.stdout) context around
parsing; @with_argparser already uses it. I'd like to propose a focused fix with these
regression tests after maintainer feedback. No PR has been opened for this report. Searches
of the current queue and relevant closed reports did not identify the same routing bug;
please point out any overlap or preferred approach.

AI assistance was used for the investigation, this report, and preparing/running the local
reproduction and tests.

Activity

  1. KelvinChung2000 commented on Oct 17, 2026

    @KelvinChung2000
    Contributor

    If you would like to propose a fix, I am happy to review it.

  2. AryanRG commented on Oct 17, 2026

    @AryanRG
    Author

    Thanks for the invitation. I have a focused fix for the annotated help output stream, with red-before/green-after regression tests. I’ll open a PR linked to this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions