Skip to content

Print help caused by a command line error on stderr - #1156

Open
eastagiletracker wants to merge 1 commit into
Backblaze:masterfrom
eastagiletracker:agile-board/error-help-to-stderr
Open

Print help caused by a command line error on stderr#1156
eastagiletracker wants to merge 1 commit into
Backblaze:masterfrom
eastagiletracker:agile-board/error-help-to-stderr

Conversation

@eastagiletracker

Copy link
Copy Markdown

This PR proposes printing the help text that accompanies a command line syntax error on stderr instead of stdout (Fixes #493). We include this PR work along with a full history of your repo at https://eastagiletracker.com/projects/281. You can sign in with your GitHub ID to claim ownership of the project.

The defect

B2ArgumentParser.error() calls self.print_help(), which writes to stdout, and only the one-line prog: error: ... message reaches stderr through self.exit(2, ...). Every argument parsing failure therefore emits several kilobytes of help on the success channel, so a mistyped command corrupts redirected or piped output. This is the second half of what was described in the issue thread: help requested explicitly already goes to stdout, but the help printed because of an error still goes there too.

Reproduced on master at 87e3e14 with the installed console script:

$ b2 sync >out.txt 2>err.txt ; echo "exit=$?"
exit=2
$ wc -c <out.txt ; wc -c <err.txt
9607
75
$ head -c 16 out.txt
b2 sync [-h] [

9.6 kB of help text lands in out.txt, which is the file the user intended to hold command output, while the 75 bytes that actually describe the failure go to stderr. The same applies to b2 ... | jq and, as reported in the thread, to PowerShell, which treats the whole stream as an error.

The change

error() now passes sys.stderr to print_help(). That is the only behavioural line; the message, the exit status and the help formatting are untouched.

This does change an observable CLI contract, so to be explicit about the boundary: help requested on purpose is unchanged. --help, --help-all and <command> --help still write to stdout and still exit 0. Only output that accompanies a non-zero exit moves to stderr, which matches how the rest of the tool already reports errors, and which is the convention sort, cut and wc follow. A script that parsed help out of stdout after a failed invocation would need to read stderr, but such a script is already distinguishing the case by exit status 2.

After the change:

$ b2 sync >out.txt 2>err.txt ; echo "exit=$?"
exit=2
$ wc -c <out.txt ; wc -c <err.txt
0
9682

Verification

Three regression cases were added to test/unit/console_tool/test_help.py, covering an unrecognised top-level argument, missing required arguments, and an unrecognised subcommand argument. Each asserts that stdout is empty and that the error text and the option list are on stderr. They fail on the unmodified tree and pass with the change:

$ git checkout master -- b2/_internal/arg_parser.py
$ pytest test/unit/console_tool/test_help.py -q
3 failed, 3 passed
$ git checkout HEAD -- b2/_internal/arg_parser.py
$ pytest test/unit/console_tool/test_help.py -q
6 passed

A companion test asserts the control case — that --help still writes to stdout and leaves stderr empty — and passes in both states, so the two paths are pinned apart rather than merely moved.

The full unit suite was run before and after on the same tree: 378 passed before, 382 passed after (the four added cases), with an identical failure set both times. Two test_install_autocomplete cases fail on this machine before any change, from the local shell configuration, and are unrelated. ruff check and ruff format --check pass on both touched files. A changelog.d fragment is included per CONTRIBUTING.

How this was managed

Your issues, pull requests and milestones were imported onto an agile board — 1112 stories and 17 labels — and this work was tracked there as some b2 clip help requests write to stderr instead of stdout, on the board at https://eastagiletracker.com/projects/281.

board

If you'd rather not receive contributions like this, reply no-more-prs on this pull request and we won't open any further ones on your repositories.


Lawrence W. Sinclair
CEO / East Agile
linkedin.com/in/lwsinclair/
eastagile.com

Argument parsing errors printed the full help message to stdout while
only the one line error went to stderr. A mistyped command therefore
wrote several kilobytes of help into redirected or piped output, e.g.
`b2 sync > out.txt` left 9.6 kB of help text in out.txt.

Help requested explicitly with --help/--help-all keeps going to stdout;
only the help that accompanies an error moves to stderr.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

some b2 clip help requests write to stderr instead of stdout

1 participant