Wandering Thoughts archives

2005-10-22

A gotcha with Python and Unix signals

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 trys?), 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.)

python/SignalExceptionSurprise written at 02:06:04; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.