I ran into the same Python problem as this fellow. Namely: he’s written a script that dumps lines to stdout, and then runs
my_script.py | head
and gets this:
Traceback (most recent call last): File "/home/slaniel/bin/my_script.py", line 25, in main() File "/home/slaniel/bin/my_script.py", line 22, in main print "".join(["%s %s\n" % (value, key) for key, value in sorted_list]) IOError: [Errno 32] Broken pipe
I.e., Python still has data in the pipe, ready to go to stdout
, but it can’t send it because head(1)
exited. So my_script.py
gets SIGPIPE
, and Python traps that as an IOError
exception. The solution is straightforward:
from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE,SIG_DFL)
This DFL thing is new to me:
signal.SIG_DFL
This is one of two standard signal handling options; it will simply perform the default function for the signal. For example, on most systems the default action for SIGQUIT is to dump core and exit, while the default action for SIGCHLD is to simply ignore it.
If I’m reading that right, Python replaces the default SIGPIPE
behavior with a thrown exception. To make the signal yield the system default, you need to tell Python explicitly to do that.
Two questions:
- Why would Python do this? Is the general logic that it’s trying to “internalize” systemwide behaviors? Maybe it wants a script to be “write once, run anywhere”, so it can’t just accept the systemwide behavior. Instead, it has to turn external system events (like
SIGPIPE
) into internal program behaviors (like exceptions). Is that the idea? - I don’t want to have to tell every one of my scripts to exit silently when it receives
SIGPIPE
. So I would prefer not to write
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL)
in every script that I ever produce. Do people have a general approach here? E.g., every script does animport Steve_lib
(or your own equivalent) that sets up the expected signal-handling defaults?
So, part of the issue is that you might get a SIGPIPE for file descriptors besides stdout. If python just silently died with a SIGPIPE when you wrote to some other file descriptor, then that *would* break compatibility when run on different platforms and you’d be complaining that SIGPIPE should generate an IOError by default.
One way to handle this might be that your main() should catch IOErrors that originate from SIGPIPE on stdout and then silently exit. Then, other file descriptors can catch the legit SIGPIPE errors you’re actually interested in catching without effing up your program. Having to setup that handler is a bit of a pain, but you’ll get semantics you actually want in all cases rather than something unknown. You might also be doing things like catching KeyboardInterrupt so it doesn’t dump a backtrace as well…another signal you have to handle as an exception, BTW. So, what’s one more?
LikeLike
0 Pingbacks