Python - SIGPIPE handled bug

Randall Hopper aa8vb at yahoo.com
Fri Jan 21 16:29:25 EST 2000


...or so it appears anyway.

  ---------------------------------------------------------------------------
    > python -c "for i in xrange(1000): print 'Some output'" | head -2
    Some output
    Some output
    Traceback (innermost last):
      File "<string>", line 1, in ?
    IOError: [Errno 32] Broken pipe
  ---------------------------------------------------------------------------

python getting a SIGPIPE is appropriate behavior.  "Whether" it gets a
SIGPIPE is up to the shell, in UNIX:

    http://www.deja.com/=dnc/[ST_rn=ps]/getdoc.xp?AN=567584780

That's all fine.  I have two questions:

  ---------------------------------------------------------------------------
  1) Why does SIGPIPE cause Python to throw an error exception, and call
     atexit functions?

     According to signal(2), the default C behavior should be to just _exit(2).
     So, by default, shouldn't Python just exit quietly with status 2, 
     without calling atexit functions?

  ---------------------------------------------------------------------------
  2) If SIGPIPE throwing an IOError is decided to be correct,
     what's the right way to suppress the error in Python code?  

     a) Resetting Python's SIGPIPE handling behavior back to what the C library
        defines (_exit(2)) is one option:

            from signal import signal, SIGPIPE, SIG_DFL
            signal( SIGPIPE, SIG_DFL )

        _exit(2) is now called, and no atexit functions are called.
        But we bypass exception handlers, which might not be a good thing.
        
     b) Install an SIGPIPE error handler, reset sys.exitfunc inside it, and
        then manually throw an IOError from inside the signal handler?

        Does Python have any atexits internally?  Should those be called?

     c) Or, we let the IOError bubble to the top, let all the exception
        handlers fire, and then invoke this verbosity:

            try:
              my_program()
            except IOError, x:
              if x.errno == errno.EPIPE:
                os._exit(2)
              else:
                raise

        Is this best?  Is it portable?  And is there a simpler way?

  ---------------------------------------------------------------------------

Opinions appreciated.

Thanks,

-- 
Randall Hopper
aa8vb at yahoo.com
-------------- next part --------------
# write.py - Demonstrates the hoops you have to jump through
#            to deal with SIGPIPE in Python.  This isn't right because
#            sys.exitfunc (and Python's atexits) are called.


import errno, sys

def at_exit():
  sys.stderr.write( "atexit called (a bug)\n" )

def my_program():
  for i in xrange(10000): 
    print 'Some output'

sys.exitfunc = at_exit 
try:
  my_program()
except IOError, x:
  sys.stderr.write( "Ok, now lets do some cleanup\n" )
  if x.errno == errno.EPIPE:
    sys.stderr.write( "Got a SIGPIPE!\n" )
    raise SystemExit, 2
  else:
    raise


More information about the Python-list mailing list