@contextmanager
def swallow_outputs():
    'Context manager to help consuming both stdout and stderr, and print()\n\n    stdout is available as cm.out and stderr as cm.err whenever cm is the\n    yielded context manager.\n    Internally uses temporary files to guarantee absent side-effects of swallowing\n    into StringIO which lacks .fileno.\n\n    print mocking is necessary for some uses where sys.stdout was already bound\n    to original sys.stdout, thus mocking it later had no effect. Overriding\n    print function had desired effect\n    '

    class StringIOAdapter(object):
        'Little adapter to help getting out/err values\n        '

        def __init__(self):
            kw = get_tempfile_kwargs({}, prefix='outputs')
            self._out = NamedTemporaryFile(delete=False, mode='w', **kw)
            self._err = NamedTemporaryFile(delete=False, mode='w', **kw)

        def _read(self, h):
            with open(h.name) as f:
                return f.read()

        @property
        def out(self):
            if (not self._out.closed):
                self._out.flush()
            return self._read(self._out)

        @property
        def err(self):
            if (not self._err.closed):
                self._err.flush()
            return self._read(self._err)

        @property
        def handles(self):
            return (self._out, self._err)

        def cleanup(self):
            self._out.close()
            self._err.close()
            out_name = self._out.name
            err_name = self._err.name
            from datalad import cfg
            if (cfg.getbool('datalad.log', 'outputs', default=False) and (lgr.getEffectiveLevel() <= logging.DEBUG)):
                for (s, sname) in ((self.out, 'stdout'), (self.err, 'stderr')):
                    if s:
                        pref = (os.linesep + '| ')
                        lgr.debug('Swallowed %s:%s%s', sname, pref, s.replace(os.linesep, pref))
                    else:
                        lgr.debug('Nothing was swallowed for %s', sname)
            del self._out
            del self._err
            gc.collect()
            rmtemp(out_name)
            rmtemp(err_name)

    def fake_print(*args, **kwargs):
        sep = kwargs.pop('sep', ' ')
        end = kwargs.pop('end', '\n')
        file = kwargs.pop('file', sys.stdout)
        if (file in (oldout, olderr, sys.stdout, sys.stderr)):
            try:
                sys.stdout.write((sep.join(args) + end))
            except UnicodeEncodeError as exc:
                lgr.error("Failed to write to mocked stdout, got %s, continue as it didn't happen", exc)
        else:
            oldprint(*args, sep=sep, end=end, file=file)
    from .ui import ui
    oldprint = getattr(builtins, 'print')
    (oldout, olderr) = (sys.stdout, sys.stderr)
    olduiout = ui.out
    adapter = StringIOAdapter()
    try:
        (sys.stdout, sys.stderr) = adapter.handles
        ui.out = adapter.handles[0]
        setattr(builtins, 'print', fake_print)
        (yield adapter)
    finally:
        (sys.stdout, sys.stderr, ui.out) = (oldout, olderr, olduiout)
        setattr(builtins, 'print', oldprint)
        adapter.cleanup()
Context manager to help consuming both stdout and stderr, and print()

stdout is available as cm.out and stderr as cm.err whenever cm is the
yielded context manager.
Internally uses temporary files to guarantee absent side-effects of swallowing
into StringIO which lacks .fileno.

print mocking is necessary for some uses where sys.stdout was already bound
to original sys.stdout, thus mocking it later had no effect. Overriding
print function had desired effect
@contextmanager
def swallow_outputs():
    'Context manager to help consuming both stdout and stderr, and print()\n\n    stdout is available as cm.out and stderr as cm.err whenever cm is the\n    yielded context manager.\n    Internally uses temporary files to guarantee absent side-effects of swallowing\n    into StringIO which lacks .fileno.\n\n    print mocking is necessary for some uses where sys.stdout was already bound\n    to original sys.stdout, thus mocking it later had no effect. Overriding\n    print function had desired effect\n    '

    class StringIOAdapter(object):
        'Little adapter to help getting out/err values\n        '

        def __init__(self):
            kw = get_tempfile_kwargs({}, prefix='outputs')
            self._out = NamedTemporaryFile(delete=False, mode='w', **kw)
            self._err = NamedTemporaryFile(delete=False, mode='w', **kw)

        def _read(self, h):
            with open(h.name) as f:
                return f.read()

        @property
        def out(self):
            if (not self._out.closed):
                self._out.flush()
            return self._read(self._out)

        @property
        def err(self):
            if (not self._err.closed):
                self._err.flush()
            return self._read(self._err)

        @property
        def handles(self):
            return (self._out, self._err)

        def cleanup(self):
            self._out.close()
            self._err.close()
            out_name = self._out.name
            err_name = self._err.name
            from datalad import cfg
            if (cfg.getbool('datalad.log', 'outputs', default=False) and (lgr.getEffectiveLevel() <= logging.DEBUG)):
                for (s, sname) in ((self.out, 'stdout'), (self.err, 'stderr')):
                    if s:
                        pref = (os.linesep + '| ')
                        lgr.debug('Swallowed %s:%s%s', sname, pref, s.replace(os.linesep, pref))
                    else:
                        lgr.debug('Nothing was swallowed for %s', sname)
            del self._out
            del self._err
            gc.collect()
            rmtemp(out_name)
            rmtemp(err_name)

    def fake_print(*args, **kwargs):
        sep = kwargs.pop('sep', ' ')
        end = kwargs.pop('end', '\n')
        file = kwargs.pop('file', sys.stdout)
        if (file in (oldout, olderr, sys.stdout, sys.stderr)):
            try:
                sys.stdout.write((sep.join(args) + end))
            except UnicodeEncodeError as exc:
                lgr.error("Failed to write to mocked stdout, got %s, continue as it didn't happen", exc)
        else:
            oldprint(*args, sep=sep, end=end, file=file)
    from .ui import ui
    oldprint = getattr(builtins, 'print')
    (oldout, olderr) = (sys.stdout, sys.stderr)
    olduiout = ui.out
    adapter = StringIOAdapter()
    try:
        (sys.stdout, sys.stderr) = adapter.handles
        ui.out = adapter.handles[0]
        setattr(builtins, 'print', fake_print)
        (yield adapter)
    finally:
        (sys.stdout, sys.stderr, ui.out) = (oldout, olderr, olduiout)
        setattr(builtins, 'print', oldprint)
        adapter.cleanup()