1

In Python I'm using

sys.stdout = None 

before some calls that I don't control. These calls may call some subprocesses that write to stdout.

How can I avoid this subprocesses calls to write to stdout?

Again, I don't have ownership of the code that calls the subprocess. It seems subprocess.Popen (and similar) doesn't honor sys.stdout.

Leo
  • 1,066
  • 1
  • 6
  • 19
  • https://stackoverflow.com/questions/2828953/silence-the-stdout-of-a-function-in-python-without-trashing-sys-stdout-and-resto Does this do the trick? – Uvar Aug 25 '17 at 12:25

2 Answers2

1

Yes, redirecting sys.stdout only works for python prints. When a sub-process is invoked through subprocess, python doesn't capture the output by default, and leaves the process execute normally. There's no way to remove the output from the process easily.

I suppose you could create a subprocess.py file at the same level as the python code you cannot change (or before the official subprocess.py) to change Popen contents, but that would mean import the official module from your stub module, hardcoding python path, ... Doable, but there's a simpler approach.

Here's a quick hack for python 3 that I tested and which works:

  • locate the file subprocess.py in the python installation and copy it aside the module that you cannot change (on my machine C:\python34\lib\subprocess.py)
  • add just one line in that file

the code (around line 750):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=()):
    """Create new Popen instance."""

    _cleanup()

now add (before _cleanup()):

    stderr = stdout = DEVNULL

that forces standard output and error to null device: no output

now the drawbacks:

  • dependent of the installed python version. Could work with other versions but it's not recommended to mix packages.
  • copies the whole subprocess.py file instead of just patching the needed calls

Apart from that it's a 5 minute job and it works. I recommend that you keep that as a temporary solution and you do something about this "code that cannot be changed" at some point.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
1

You could replace subprocess.Popen with a custom function that suppresses stdout and stderr:

import subprocess
import inspect

def Popen(*args, **kwargs):
    sig = inspect.signature(real_popen)
    bound_args = sig.bind(*args, **kwargs).arguments
    bound_args['stdout'] = subprocess.DEVNULL
    bound_args['stderr'] = subprocess.DEVNULL
    return real_popen(**bound_args)

real_popen = subprocess.Popen
subprocess.Popen = Popen

Caveat:

If you have code that attempts to read the process's output, it will fail.

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149