Управление stdout/stderr от Jython


Я вызываю функцию в библиотеке java из jython, которая печатает в stdout. Я хотел бы подавить этот вывод из сценария jython. Я ставлю на Python идиома замена сис.stdout с файлом, подобным объекту (StringIO), но это не захватывает выходные данные библиотеки java. Я предполагаю, что sys.stdout не влияет на программу java. Существует ли стандартное соглашение для перенаправления или подавления этого вывода программно в jython? Если нет, то какими способами я могу достичь вот это?

2 7

2 ответа:

Вы можете использовать System.setOut, например:

>>> from java.lang import System 
>>> from java.io import PrintStream, OutputStream
>>> oldOut = System.out
>>> class NoOutputStream(OutputStream):         
...     def write(self, b, off, len): pass      
... 
>>> System.setOut(PrintStream(NoOutputStream()))
>>> System.out.println('foo')                   
>>> System.setOut(oldOut)
>>> System.out.println('foo')                   
foo
Обратите внимание, что это не повлияет на вывод Python, потому что Jython захватывает System.out, когда он запускается, чтобы вы могли переназначить sys.stdout, как и ожидалось.

Я создал контекстный менеджер для имитации (Python3) contextlib redirect_stdout (суть здесь):

'''Wouldn't it be nice if sys.stdout knew how to redirect the JVM's stdout? Shooting star.
        Author: Sean Summers <seansummers@gmail.com> 2015-09-28 v0.1
        Permalink: https://gist.githubusercontent.com/seansummers/bbfe021e83935b3db01d/raw/redirect_java_stdout.py
'''

from java import io, lang

from contextlib import contextmanager

@contextmanager
def redirect_stdout(new_target):
        ''' Context manager for temporarily redirecting sys.stdout to another file or file-like object
                see contextlib.redirect_stdout documentation for usage
        '''

        # file objects aren't java.io.File objects...
        if isinstance(new_target, file):
                new_target.close()
                new_target = io.PrintStream(new_target.name)
        old_target, target = lang.System.out, new_target
        try:
                lang.System.setOut(target)
                yield None
        finally:
                lang.System.setOut(old_target)