sys.__stdout__ works but sys.stdout does not

621 views Asked by At

There is a function named redirect which temporarily redirects operations on file source to file target.

    def redirect(source, target):
    source.flush()
    fd = source.fileno()
    with os.fdopen(os.dup(fd), source.mode) as source2:
        os.dup2(target.fileno(), fd)
        try:
            yield
        finally:
            source.flush()
            os.dup2(source2.fileno(), fd)

It was being called from the same module as

    with tempfile.TemporaryFile() as tmp:
        with redirect(sys.stdout, tmp), nogil:

Upon compiling, it used to generate an AttributeError

AttributeError: StringIO instance has no attribute 'fileno'

at the line fd = source.fileno().

But when I replaced sys.stdout with sys.__stdout__, there was no such error, and the tests passed successfully.

Now I'm really puzzled, why __stdout__ worked but not stdout.

1

There are 1 answers

0
AbdealiLoKo On BEST ANSWER

As Greg mentioned in the comments, that wouldn't work. What I normally do is temporarily change my stdout.

@contextmanager
def replace_stdout(replacement):
    _stdout = sys.stdout
    sys.stdout = replacement
    try:
        yield
    finally:
        sys.stdout = _stdout

And use that context manager with :

with tempfile.TemporaryFile() as tmp:
    with replace_stdout(sys.stdout, tmp):

This usages doesn't care whether the initial stdout has a FD or not.