¿Cómo redirigir stderr en Python?

Me gustaría registrar toda la salida de un script de Python. Lo intenté:

import sys log = [] class writer(object): def write(self, data): log.append(data) sys.stdout = writer() sys.stderr = writer() 

Ahora, si “imprimo ‘algo'” se registra. Pero si cometo, por ejemplo, algún error de syntax, diga “imprimir ‘algo #”, no se registrará, sino que entrará en la consola.

¿Cómo capturo también los errores del intérprete de Python?

Vi una posible solución aquí:

http://www.velocityreviews.com/forums/showpost.php?p=1868822&postcount=3

pero el segundo ejemplo inicia sesión en / dev / null, esto no es lo que quiero. Me gustaría registrarlo en una lista como mi ejemplo anterior o StringIO o similares …

Además, preferiblemente no quiero crear un subproceso (y leer su stdout y stderr en un hilo separado).

No puede hacer nada en el código Python que pueda capturar errores durante la comstackción de ese mismo código. Como pudo Si el comstackdor no puede terminar de comstackr el código, no lo ejecutará, por lo que su redirección aún no ha tenido efecto.

Ahí es donde entra su subproceso (no deseado). Puede escribir el código de Python que redirige la salida estándar, y luego invoca al intérprete de Python para comstackr otra pieza de código.

Tengo un software que escribí para el trabajo que captura stderr en un archivo como este:

 import sys sys.stderr = open('C:\\err.txt', 'w') 

así que definitivamente es posible.

Creo que tu problema es que estás creando dos instancias de escritor.

Tal vez algo más como:

 import sys class writer(object): log = [] def write(self, data): self.log.append(data) logger = writer() sys.stdout = logger sys.stderr = logger 

No puedo pensar en una manera fácil. El error estándar del proceso de python está viviendo en un nivel más bajo que un objeto de archivo de python (C vs. python).

Podría envolver el script de python en un segundo script de python y usar subprocess.Popen. También es posible que puedas extraer algo de magia como esta en un solo script:

 import os import subprocess import sys cat = subprocess.Popen("/bin/cat", stdin=subprocess.PIPE, stdout=subprocess.PIPE) os.close(sys.stderr.fileno()) os.dup2(cat.stdin.fileno(), sys.stderr.fileno()) 

Y luego use select.poll () para revisar cat.stdout regularmente para encontrar la salida.

Sí, eso parece funcionar.

El problema que preveo es que la mayoría de las veces, algo impreso en stderr por python indica que está a punto de salir. La forma más habitual de manejar esto sería a través de excepciones.

———Editar

De alguna manera me perdí la función os.pipe ().

 import os, sys r, w = os.pipe() os.close(sys.stderr.fileno()) os.dup2(w, sys.stderr.fileno()) 

Entonces lee de r

En realidad, si está usando linux / mac os, puede usar la redirección de archivos para hacer eso. Por ejemplo, si va a ejecutar “a.py” y grabar todos los mensajes que generará en el archivo “a.out”, simplemente será

python a.py 2>&1 > a.out

La primera parte redirige stderr a stdout, y la segunda redirige a un archivo llamado a.out.

Para obtener una lista más larga de operadores de redireccionamiento en Linux / Unix, consulte https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file

Desde Python 3.5 puedes usar contextlib.redirect_stderr

 with open('help.txt', 'w') as f: with redirect_stdout(f): help(pow) 
 import sys import tkinter # ******************************************** def mklistenconsswitch(*printf: callable) -> callable: def wrapper(*fcs: callable) -> callable: def newf(data): [prf(data) for prf in fcs] return newf stdoutw, stderrw = sys.stdout.write, sys.stderr.write funcs = [(wrapper(sys.stdout.write, *printf), wrapper(sys.stderr.write, *printf)), (stdoutw, stderrw)] def switch(): sys.stdout.write, sys.stderr.write = dummy = funcs[0] funcs[0] = funcs[1] funcs[1] = dummy return switch # ******************************************** def datasupplier(): i = 5.5 while i > 0: yield i i -= .5 def testloop(): print(supplier.__next__()) svvitch() root.after(500, testloop) root = tkinter.Tk() cons = tkinter.Text(root) cons.pack(fill='both', expand=True) supplier = datasupplier() svvitch = mklistenconsswitch(lambda text: cons.insert('end', text)) testloop() root.mainloop() 

Python no ejecutará su código si hay un error. Pero puede importar su script en otro script y excepciones de captura. Ejemplo:

Script.py

 print 'something# 

FinalScript.py

 from importlib.machinery import SourceFileLoader try: SourceFileLoader("main", " 

Para agregar a la respuesta de Ned, es difícil capturar los errores sobre la marcha durante la comstackción.

Puede escribir varias declaraciones de impresión en su script y puede salir a un archivo, dejará de escribir en el archivo cuando se produce el error. Para depurar el código, puede verificar la última salida registrada y verificar su script después de ese punto.

Algo como esto:

 # Add to the beginning of the script execution(eg: if __name__ == "__main__":). from datetime import datetime dt = datetime.now() script_dir = os.path.dirname(os.path.abspath(__file__)) # gets the path of the script stdout_file = script_dir+r'\logs\log'+('').join(str(dt.date()).split("-"))+r'.log' sys.stdout = open(stdout_file, 'w') 

Esto creará un archivo de registro y transmitirá las declaraciones de impresión al archivo.

Nota: tenga cuidado con los caracteres de escape en su ruta de archivo mientras concatena con script_dir en la segunda línea de la última en el código. Es posible que desee algo similar a la cadena en bruto. Puede comprobar este hilo para esto.