Click: Prompts write to STDOUT

Created on 20 Feb 2015  Â·  18Comments  Â·  Source: pallets/click

If you use a prompt option (with prompt=True), the prompt itself gets written to STDOUT. This is a different behaviour as in other programs, where the prompt is neither written to STDOUT nor STDERR (I don't know exactly, how they actually do it).

This is especially bad if you want to pipe STDOUT into a file: You will get the data alongside the password prompt.

So, please at least put the prompt on STDERR.

bug

Most helpful comment

Please update the docs to:

  • warn that Click prompts are written to stdout;
  • document workarounds if the user wants their script to support redirecting stdout.

Example use cases needing workarounds:

cli_script.py | cat
val="$(cli_script.py)"; echo "$val"

Example workarounds addressing the above use cases:

Password options:

@click.option(
    "--foo-password",
    default=functools.partial(getpass.getpass, "Foo password: "))

Other options:

def prompt_for_val(prompt):
    # input() has no option to use stderr...
    print(prompt, end="", file=sys.stderr)
    return input()

...

@click.option(
    "--foo-option",
    default=functools.partial(prompt_for_val, "Foo option: "))

All 18 comments

i suppose a prompt should go to the controlling terminal in all cases?

Yes, right. That's what I just found out, too. :)

The cause of this is in https://github.com/mitsuhiko/click/blob/master/click/termui.py#L69.

The prompt is simply echo'ed there.

if you got an idea how to properly do that please create a PR,
else we'll have to figure later (as in when there is time)

Will do that. I got an idea regarding Unixes and would leave Windows with the current method, if that's okay.

Am 21.02.2015 um 17:14 schrieb Ronny Pfannschmidt [email protected]:

if you got an idea how to properly do that please create a PR,
else we'll have to figure later (as in when there is time)

—
Reply to this email directly or view it on GitHub.

sound fabulous, thanks in advance :+1:

I wonder how click's testing utilities could cope with that.

i suspect there is need for pexpect

I got an idea regarding Unixes and would leave Windows with the current method, if that's okay.

@dploeger Any update on this? Cement also seems to have this problem if that boosts your motivation :)

@untitaker No, sorry. :) I cannot find the time for that currently.

I wonder what is the correct behavior for this... You might or might not have a controlling terminal, and stdio might or might not be redirected. Prompting should do something that makes sense in all cases. I have sometimes seen users use interactive programs by feeding them answers to prompts from stdin...

After all, this does use Python's raw_input/input, which will use readline when sys.std* is not redirected, and is a tty, and otherwise prints the prompt to stdout. So Python's own prompting facility prints to stdout, which is probably why click prints it there in the first place.

If a different behavior is to be implemented here, we should consider what other programs do, in the various cases, and if we stop using Python's raw_input/input, we should consider how we fit in readline into that too.

Please update the docs to:

  • warn that Click prompts are written to stdout;
  • document workarounds if the user wants their script to support redirecting stdout.

Example use cases needing workarounds:

cli_script.py | cat
val="$(cli_script.py)"; echo "$val"

Example workarounds addressing the above use cases:

Password options:

@click.option(
    "--foo-password",
    default=functools.partial(getpass.getpass, "Foo password: "))

Other options:

def prompt_for_val(prompt):
    # input() has no option to use stderr...
    print(prompt, end="", file=sys.stderr)
    return input()

...

@click.option(
    "--foo-option",
    default=functools.partial(prompt_for_val, "Foo option: "))

@stephen-dexda thanks for your input, but I'd see the issue fixed rather than officially document a bunch of confusing workarounds.

@davidism at the very least the docs should warn that stdout is used for prompts, since script CLIs are where authors/users will most expect proper separation between user interaction (prompts) and final output (suitable for redirection to subsequent commands).

I'd rather see it fixed too, but this issue has been open for 5 years, so it was suggestion to help users of Click in the interim.

It's been open for 5 years because no one has submitted a patch to fix it. If this is something that's important to you, I'd be happy to review a PR. According to @segevfiner's previous comment, there is a lot to consider in any fix, including that Python itself prompts to stdout.

I know about the issue and workarounds so it's much of a muchness to me. In the interim, it's reasonable to document for (other) users of Click about the behaviour, since it differs from the behaviour of other CLI utilities, and breaks various use cases.

Python itself prompts to stdout.

https://bugs.python.org/issue1927

Closing in favor of continuing to use the input handling provided by Python.

In which case please update the documentation.

Was this page helpful?
0 / 5 - 0 ratings