d3pd d3pd - 7 months ago 10
Python Question

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()

Answer

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