-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-33550: Warn not to set SIGPIPE to SIG_DFL #6773
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -503,3 +503,37 @@ be sent, and the handler raises an exception. :: | |
|
||
signal.alarm(0) # Disable the alarm | ||
|
||
Note on SIGPIPE | ||
--------------- | ||
|
||
Piping output of your program to tools like :manpage:`head(1)` will | ||
cause a :const:`SIGPIPE` signal to be sent to your process when the receiver | ||
of its standard output closes early. This results in an exception | ||
like :code:`BrokenPipeError: [Errno 32] Broken pipe`. To handle this | ||
case, wrap your entry point to catch this exception as follows:: | ||
|
||
import os | ||
import sys | ||
|
||
def main(): | ||
try: | ||
# simulate large output (your code replaces this loop) | ||
for x in range(10000): | ||
print("y") | ||
# flush output here to force SIGPIPE to be triggered | ||
# while inside this try block. | ||
sys.stdout.flush() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps it would be clearer if you made it an indefinite while True loop; then you wouldn’t need the flush There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The goal here is to give a recipe which covers common uses. Showing that it's important to use sys.stdout.flush() because not all programs are an infinite loop, a significant portion do a single task outputting some output and that flush is required to avoid the pipe error. |
||
except BrokenPipeError: | ||
# Python flushes standard streams on exit; redirect remaining output | ||
# to devnull to avoid another BrokenPipeError at shutdown | ||
devnull = os.open(os.devnull, os.O_WRONLY) | ||
os.dup2(devnull, sys.stdout.fileno()) | ||
sys.exit(1) # Python exits with error code 1 on EPIPE | ||
|
||
if __name__ == '__main__': | ||
main() | ||
|
||
Do not set :const:`SIGPIPE`'s disposition to :const:`SIG_DFL` | ||
in order to avoid :exc:`BrokenPipeError`. Doing that would cause | ||
your program to exit unexpectedly also whenever any socket connection | ||
is interrupted while your program is still writing to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I don't think this is suitable for the signal module documentation. Maybe we can create a HOWTO document for signals? A HOWTO document would also allow us adding more best practices in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Until we have such document, I'm fine putting this in the documentation as is so it's searchable.