Подтвердить что ты не робот

Перенаправление FORTRAN (вызванного через F2PY) вывода в Python

Я пытаюсь выяснить, как перенаправить вывод из некоторого кода FORTRAN, для которого я создал интерфейс Python, используя F2PY. Я пробовал:

from fortran_code import fortran_function
stdout_holder = sys.stdout
stderr_holder = sys.stderr
sys.stdout = file("/dev/null","w")
fortran_function()
sys.stdout.close()
sys.stderr.close()
sys.stdout = stdout_holder
sys.stderr = stderr_holder

Это де-факто метод перенаправления вывода в Python, но в этом случае он не работает (т.е. вывод все равно отображается).

Я нашел почтовую рассылку с 2002 года, в которой говорилось: "Можно читать сообщения с устройств pts, например, ttysnoop делает это". Информация о ttysnoop кажется довольно сложной для поиска в Интернете (я не думаю, что она была обновлена ​​через несколько лет, например, первый результат в Google для "ttysnoop" имеет только мертвые ссылки на tarballs, RPM и .deb), и этот запрос для порта в OS X получил ответ "Не повезло, для этого требуются некоторые специфичные для Linux функции utmp, которые я не могу создать".

Я открыт для любых предложений о том, как перенаправить вывод (ему не нужно использовать ttysnoop).

Спасибо!

4b9b3361

Ответ 1

Фреймы stdin и stdout наследуются совместно используемой библиотекой C.

from fortran_code import fortran_function
import os

print "will run fortran function!"

# open 2 fds
null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)]
# save the current file descriptors to a tuple
save = os.dup(1), os.dup(2)
# put /dev/null fds on 1 and 2
os.dup2(null_fds[0], 1)
os.dup2(null_fds[1], 2)

# *** run the function ***
fortran_function()

# restore file descriptors so I can print the results
os.dup2(save[0], 1)
os.dup2(save[1], 2)
# close the temporary fds
os.close(null_fds[0])
os.close(null_fds[1])

print "done!"

Ответ 2

Здесь контекстный менеджер, который я недавно написал и нашел полезным, потому что у меня была аналогичная проблема с distutils.ccompiler.CCompiler.has_function во время работы над pymssql. Я также использовал подход дескриптора файла, но я использовал контекстный менеджер. Вот что я придумал:

import contextlib


@contextlib.contextmanager
def stdchannel_redirected(stdchannel, dest_filename):
    """
    A context manager to temporarily redirect stdout or stderr

    e.g.:


    with stdchannel_redirected(sys.stderr, os.devnull):
        if compiler.has_function('clock_gettime', libraries=['rt']):
            libraries.append('rt')
    """

    try:
        oldstdchannel = os.dup(stdchannel.fileno())
        dest_file = open(dest_filename, 'w')
        os.dup2(dest_file.fileno(), stdchannel.fileno())

        yield
    finally:
        if oldstdchannel is not None:
            os.dup2(oldstdchannel, stdchannel.fileno())
        if dest_file is not None:
            dest_file.close()

Контекст, почему я создал это, находится в этом сообщении в блоге. Похоже на твое мнение.

Я использую его так: setup.py:

with stdchannel_redirected(sys.stderr, os.devnull):
    if compiler.has_function('clock_gettime', libraries=['rt']):
        libraries.append('rt')