Python likes to handle things through exceptions. As part of this, on Unix it does two important signal changes; it ignores
SIGPIPE
and catches
SIGINT
. Each of these can make a Python program report apparent errors where a normal Unix command-line program would just silently exit.
This matters if you want to write a Python program that will play well in an ordinary command-line environment, alongside things like
cat
,
sed
, and
awk
.
First, people expect that they can ^C a Unix command-line program and have it just quietly stop. Python's default behavior turns this into a
KeyboardInterrupt
exception, which your program is probably not catching; the user will get a multi-line traceback.
Second and more important, Python ignoring
SIGPIPE
means that your program will get an
OSError
exception if it writes to a pipe that has closed. Pipes close all the time in Unix command pipelines when you write things like:
generate | mangle.py | head -10
Since
head
exits after it's read and printed ten lines, further output from
mangle.py
is probably going to get an
OSError
. If you didn't handle it (do you guard
print
statements with
try
s?), the person running this will see a traceback on standard error. People tend to get irritated when their clean output is messed up with 'error' messages.
(
head
is not the only program that will do this, and it doesn't necessarily happen all the time. Consider what happens when you feed the output to a pager and quit after seeing the first screen.)
The technique I use for this is:
from signal import signal, \ SIGPIPE, SIGINT, SIG_DFL, \ default_int_handler signal(SIGPIPE, SIG_DFL) s = signal(SIGINT, SIG_DFL) if s != default_int_handler: signal(SIGINT, s)
Checking what
SIGINT
is set to is necessary because when your Python program is being run via
nohup
and similar things,
SIGINT
will be set to
SIG_IGN
. If we always set
SIGINT
to
SIG_DFL
, we would defeat
nohup
and irritate the user even more.
(This little thing with
SIGINT
is not unique to Python; it's something you should watch out for in any program where you're setting a
SIGINT
handler explicitly. Python itself does it the right way on startup, leaving a
SIG_IGN
setting alone.)