Search code examples
pythonstdoutstderrcontextmanager

Why does devnull not work at hiding console output when it is defined within this context manager?


I have a context manager defined for the purpose of "silencing" the output of some Python code by redefining stdout and stderr temporarily.

When devnull is defined in the main function of the code, the output of the code is silenced successfully, however, when devnull is defined in the context manager, the output of the code is not silenced.

Why is this? How could the context manager silence the output while also defining devnull?

import os
import sys

def main():

    print("hello")

    devnull = open(os.devnull, "w")
    with silence(
        stdout = devnull,
        stderr = devnull
        ):
        print("there")

    print("world")

class silence(object):

    def __init__(
        self,
        stdout = None,
        stderr = None
        ):
        if stdout == None and stderr == None:
            devnull = open(os.devnull, "w")
        self._stdout = stdout or sys.stdout
        self._stderr = stderr or sys.stderr

    def __enter__(
        self
        ):
        self.old_stdout = sys.stdout
        self.old_stderr = sys.stderr
        self.old_stdout.flush()
        self.old_stderr.flush()
        sys.stdout = self._stdout
        sys.stderr = self._stderr

    def __exit__(
        self,
        exc_type,
        exc_value,
        traceback
        ):
        self._stdout.flush()
        self._stderr.flush()
        sys.stdout = self.old_stdout
        sys.stderr = self.old_stderr

if __name__ == "__main__":
    main()

Solution

  • In your __ init __ method, when the stderr and stdout arguments are None you define devnull but you do not assign this value to stderr and stdout. Consequently stderr and stdout are falsey and so the output streams remain as sys.stderr and sys.stdout.

    class silence(object):
    
        def __init__(
            self,
            stdout = None,
            stderr = None
            ):
            if stdout == None and stderr == None:
                devnull = open(os.devnull, "w")
                # Assign devnull to stdout and stderr
                stdout = devnull
                stderr = devnull
            self._stdout = stdout or sys.stdout
            self._stderr = stderr or sys.stderr