2009-06-10 7 views
11

Estoy intentando descubrir cómo redirigir la salida desde algún código FORTRAN para el que he generado una interfaz Python mediante F2PY. He intentado:Redireccionando salida FORTRAN (llamada mediante F2PY) en Python

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 

Este es el método de facto de redirigir la salida en Python, pero no parece funcionar en este caso (es decir, la salida se muestra de todos modos).

Encontré a mailing list post from 2002 diciendo que "es posible leer mensajes de dispositivos pts, por ejemplo ttysnoop hace esto". La información sobre ttysnoop parece ser bastante difícil de encontrar en línea (no creo que se haya actualizado en algunos años, por ejemplo, the first result on Google for "ttysnoop" tiene enlaces muertos a archivos tar, RPM y .deb), y this request for a port to OS X recibió la respuesta " Sin suerte, requiere algunas funciones utmp específicas de Linux que no puedo crear ".

Estoy abierto a cualquier sugerencia sobre cómo redirigir la salida (no tiene que usar ttysnoop).

Gracias!

+1

¿Seguro la salida FORTRAN no va a stderr en lugar de la salida estándar? –

+0

Sí, intenté redirigirlo también, y obtuve el mismo resultado. – srunni

Respuesta

17

stdin y stdout fds son heredados por la biblioteca compartida 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!" 
+0

¿Suprimirá este stderr también? Si no, ¿cómo se puede lograr eso? – srunni

+0

@aberration: no lo hayas probado con ningún programa adicional que escriba a stderr. – nosklo

+0

Lo probé y parece mostrar texto escrito en stderr. – srunni

4

Aquí hay una context manager que escribí recientemente y encontré útil, porque estaba teniendo un problema similar con distutils.ccompiler.CCompiler.has_function mientras se trabaja en pymssql. También usé el enfoque del descriptor de archivo, pero utilicé un context manager. Esto es lo que ocurrió:

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() 

El contexto para eso he creado esto es a this blog post. Similar a la tuya, creo.

que utilizar de esta manera en un setup.py:

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