-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle SIGPIPE in click.echo(). #626
Conversation
When the output of a click program is sent to another program via a pipe, and the pipe is closed prematurely, click.echo() was printing an exception backtrace instead of silently exiting like most command line utilities.
Any interest in this fix? |
@@ -1,5 +1,6 @@ | |||
import os | |||
import sys | |||
import errno |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
LGTM, but I'd rather have someone who did some actual click development look over it. General suggestion: Squash those three commits into a single one. The last two just fix issues in the initial one after all, no need for that to be part of the project's permanent history ;) |
I thought commit squashing was up to whoever merged the branch... https://github.com/blog/2141-squash-your-commits I can squash the commits if that is preferable. |
True, we can do it too. Forgot about that ;) |
This doesn't silently exit, it swallows the exception and lets the application continue. IMO SIGPIPE should not be catched on this level but much further up (somewhere near subcommand dispatch) and then the traceback suppressed (but still exiting). |
Oops... I'm missing a I'll take a look at subcommand dispatch and see if I can figure out where you mean. |
I think here: https://github.com/pallets/click/blob/master/click/core.py#L700 @mitsuhiko Do you agree this is the proper way to handle |
Pushed something better... |
Ah, and now I read your comment and I see your suggestion is probably better... |
Something like this? |
Yeah, but is |
I was just googling that... it seems exiting -1 might be better... I tried a few system utilities and they seem to exit 0. I was about to go read POSIX :) |
I think we're supposed to raise Abort. |
The problem with raising Abort is that it prints "Aborted!" to stderr. This is undesirable for things like piping the output to |
Fair enough, then |
Okay, I pushed that. BTW, I'm so counting on you squashing all this mess ;) |
Is this acceptable now? |
I'll probably merge in a few days. It looks fine to me, but code review at On Fri, Sep 16, 2016 at 11:10:14AM -0700, Oscar Bonilla wrote:
|
Although I agree that I have a bit of code that's doing try:
click.echo(message, nl=newline, err=write_to_stderr)
except IOError as err:
if err.errno is errno.EPIPE:
pass
else:
raise So that I can maintain my promises about exit codes. This would be, to me, an acceptable alternative: try:
click.echo(message, nl=newline, err=write_to_stderr, handle_epipe=False)
except IOError:
# a reraised IOError from inside of click.echo! Must be EPIPE
pass What I object to is being asked to do this: try:
click.echo(message, nl=newline, err=write_to_stderr)
except SystemExit:
# I guess this was an EPIPE?
pass As a caller into set -o pipefail
mycommand | head -n 20 | grep 'importantstring' If supporting a pipeline like that is a priority for |
Your code doesn't have to change since SystemExit is raised somewhere completely different than from within echo. The PR title is now wrong. On 17 September 2016 19:39:29 CEST, Stephen Rosen notifications@github.com wrote:
Sent from my Android device with K-9 Mail. Please excuse my brevity. |
Thanks! Please add yourself to AUTHORS if you want! |
@untitaker Thanks for pointing out that this handling is, in fact, safe for callers of Please correct me if I'm wrong, but as I understand it this catches an EPIPE that makes its way up to Anyway, as always, thanks for this excellent CLI toolkit. |
Sorry, yes, I forgot to rename the PR and a same-named commit is now in master :( On Mon, Sep 19, 2016 at 10:25:29AM -0700, Stephen Rosen wrote:
|
@untitaker i just discovered this merge and I'm not particularly happy with this because this captures all sigpipes, so even on sockets. Also not sure if click should handle this by default like this. At least maybe make it optional? |
Any way of checking if SIGPIPE was caused by stdin/stdout/stderr? I don't think getting a traceback in these cases is something you'd want |
No, not really. You can only catch down individual writes (like in echo) and rethrow it. |
In which situation would you have a SIGPIPE from e.g. a socket?
I'd vote for optional since I think this is still reasonable default behavior
(assuming more fine-grained handling isn't possible).
…On Wed, Sep 20, 2017 at 12:04:58PM -0700, Armin Ronacher wrote:
@untitaker i just discovered this merge and I'm not particularly happy with this because this captures *all* sigpipes, so even on sockets. Also not sure if click should handle this by default like this. At least maybe make it optional?
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#626 (comment)
|
You get a sigpipe when the socket is not connected and you write to it. |
Ah damn. Feel free to revert then.
In general I would say that Click could use some sort of exception handling
like it's known from webframeworks, but that's a different topic.
…On Wed, Sep 20, 2017 at 07:14:15PM +0000, Armin Ronacher wrote:
You get a sigpipe when the socket is not connected and you write to it.
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#626 (comment)
|
@untitaker what about us wrapping both text and binary streams and augment the exception with |
I thought about that too but that's monkeypatching. Having it in click.echo would be less surprising I think.
…On 21 September 2017 09:14:17 GMT+02:00, Armin Ronacher ***@***.***> wrote:
@untitaker what about us wrapping both text and binary streams and
augment the exception with `from_stdio = True`? Then we can capture
that only by default.
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#626 (comment)
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
|
We could also raise a subclass of |
Whatever you think is best, however I dont think people will apprechiate us patching stdio even if it behaves almost the same.
…On 21 September 2017 10:35:18 GMT+02:00, Armin Ronacher ***@***.***> wrote:
We could also raise a subclass of `IOError`.
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#626 (comment)
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
|
@untitaker the proposal is not to patch stdio but to change our wrappers. We already use wrappers for the unicode support and there are already accessors for getting binary streams. We can trivially further customize those streams. |
Sure, I'm totally fine with echo rewrapping this exception.
…On 23 September 2017 11:37:20 GMT+02:00, Armin Ronacher ***@***.***> wrote:
@untitaker the proposal is not to patch stdio but to change our
wrappers. We already use wrappers for the unicode support and there are
already accessors for getting binary streams. We can trivially further
customize those streams.
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#626 (comment)
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.
|
When the output of a click program is sent to another program via a
pipe, and the pipe is closed prematurely, click.echo() was printing an
exception backtrace instead of silently exiting like most command line
utilities.
Fixes: #625