Redirecting stderr for extension modules

Donn Cave donn at u.washington.edu
Thu May 15 13:48:02 EDT 2003


Quoth Michael Pyle <mpyle at legato.com>:
... [HTML version omitted]
| I've been trying to find a way to redirect the stderr output of a function
| in a C extension module. What I'd like to create is a function that can take
| a callable and capture any output to stderr that results from the execution
| of that callable. It then returns the result of the execution and the stderr
| text as a tuple. It seems like this should be pretty straight forward, but
| after a day or so of scratching my head I just can't seem to get it to work.

Your problem is that you create your redirection file as Python file
object, and then later rewind and read that file object, but as you
know, the output actually gets there by writing to unit 2.  The file
object is not aware of this data.

If it's important to you for some reason to use a file object anyway,
you could reopen it instead of just rewinding it.  But since this does
not appear to be the case, you may as well open it with os.open, and
eventually read with os.read.

    sys.stderr.flush()
    efd = os.open('stderr.txt', os.O_RDWR|os.O_CREAT|os.O_TRUNC)
    os.dup2(efd, 2)
    ...
    sz = os.lseek(efd, 0, 1)
    os.lseek(efd, 0, 0)
    stderr = os.read(efd, sz)
    os.close(efd)
    return result, stderr

	Donn Cave, donn at u.washington.edu
--------
| def Redirect( fn, *args, **kwds ):
|     """
|     Redirect( fn, ... ) -> (fn return value, stderr)
|     
|     Captures any text written to stderr from the execution of fn. fn 
|     is expected to be an extension module function.
|     """
|     fd = os.dup( 2 )
|     if fd != -1:
|         try:
|             file = open( 'stderr.txt', 'w+' )
|             os.dup2( file.fileno(), 2 )
|         except:
|             file = None
|         
|     stderr = None
|     try:
|         result = fn( *args, **kwds )
|         return result, stderr
|     finally:
|         if file:
|             file.flush()
|             file.seek( 0, 0 )
|             stderr = file.read()
|             file.close()
|         
|         if fd != -1:
|             os.dup2( fd, 2 )
|
|
| Here's the result of executing this on an extension function that only
| writes some text to stderr (using fprintf) and then returns None:
|
| >>> from util import Redirect
| [51293 refs]
| >>> from libs import legato
| [51295 refs]
| >>> Redirect( legato.stderr )
| (None, None)
| This is not a drill! Yes it is!
| [51404 refs]
| >>>^Z
|
| The interesting thing is that stderr.txt is empty, which means that my
| stderr result is None and yet once I close my redirection file and reset the
| stderr file descriptor, the text I wrote out appears. Can someone please
| give me a boot to the head and point out where I've gone wrong?
|
| Thanks.
|
| --Mike Pyle
| --Legato Systems, Inc.




More information about the Python-list mailing list