I use the following snippet to silently (redirect output from) C code called in my Python script:
from ctypes import CDLL, c_void_p
import os
import sys
class silence(object):
def __init__(self, stdout=os.devnull):
self.outfile = stdout
def __enter__(self):
sys.__stdout__.flush()
self.saved_stream = sys.stdout
self.fd = sys.stdout.fileno()
self.saved_fd = os.dup(self.fd)
self.new_stream = open(self.outfile, 'wb', 0)
self.new_fd = self.new_stream.fileno()
os.dup2(self.new_fd, self.fd)
def __exit__(self, *args):
self.saved_stream.flush()
os.dup2(self.saved_fd, self.fd)
sys.stdout = self.saved_stream
self.new_stream.close()
os.close(self.saved_fd)
libc = CDLL('libc.so.6')
with silence():
libc.printf(b'Hello from C in silence\n')
The idea is to redirect the fd associated with stdout, and replace it with one associated with the open null device. Unfortunately, in Python 3 it does not work like this:
$ python2.7 test.py
$ python3.3 -u test.py
$ python3.3 test.py
Hello from C in silence
In Python 2.7 and 3.3 with unbuffered output, it works. However, I am not sure what the main reason is. Even if buffering stdout, the call sys.saved_stream.flush()should end with a call fflush(stdout)at level C (reset output to zero device).
What part of the Python 3 I / O model do I not understand?
source
share