Перенаправление вывода FORTRAN (вызывается через F2PY) в Python - PullRequest
12 голосов
/ 10 июня 2009

Я пытаюсь выяснить, как перенаправить вывод из некоторого кода 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" содержит только мертвые ссылки на тарболы , RPM и .deb), и этот запрос на порт для OS X получил ответ: «Не повезло, ему требуются некоторые специфичные для Linux функции utmp, которые я не могу создать».

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

Спасибо!

Ответы [ 2 ]

19 голосов
/ 11 июня 2009

Stdin и stdout fds наследуются разделяемой библиотекой 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!"
4 голосов
/ 19 июля 2013

Вот менеджер контекста , который я недавно написал и нашел полезным, потому что у меня была похожая проблема с 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')
...