2011-11-08 9 views
6

Me gustaría tener acceso en tiempo real tanto a la entrada del intérprete como a los errores y a la salida estándar. Preferiblemente esta información se escribiría en un archivo, de modo que pueda sondear el archivo para ver los cambios después de que se haya ingresado cada comando de intérprete. Por ejemplo, dada una sesión intérprete:¿Cómo registrar todo lo que ocurre en una sesión de shell interactiva de Python?

>>> 5 * 7 
35 
>>> print("Hello, world!") 
Hello, world! 
>>> "Hello, world!" 
'Hello, world!' 

me gustaría ver lo siguiente en un archivo de registro:

> 5 * 7 
35 
> print("Hello, world!") 
Hello, world! 
> "Hello, world!" 
'Hello, world!' 

El formato no es importante; lo importante es que puedo buscar palabras clave en el archivo para desencadenar eventos interactivos durante la sesión.

Lo que he aprendido hasta ahora tratando de lograr esto:

módulo de Python code me permite crear un objeto InteractiveConsole, el método raw_input de los cuales puedo redefinir para iniciar la sesión en un archivo, así:

import code 
class LoggedConsole(code.InteractiveConsole): 
    def __init__(self, locals): 
    super(LoggedConsole, self).__init__(locals) 
    self.file = open('consolelog.dat', 'a') 

    def __del__(self): 
    self.file.close() 

    def raw_input(self, prompt=""): 
    data = input(prompt) 
    self.file.write(data+'\n') 
    return data 

Además, InteractiveConsole utiliza un incorporada write método para registrar los errores, que puedo redefinir a:

def write(self, data): 
    sys.stderr.write(data) 
    self.file.write(data+'\n') 

También he aprendido que el siguiente fragmento guardara todo el stdout:

class Tee(object): 
    def __init__(self): 
    self.file = open('consolelog.dat', 'a') 
    self.stdout = sys.stdout 

    def __del__(self): 
    sys.stdout = self.stdout 
    self.file.close() 

    def write(self, data): 
    self.file.write(data) 
    self.stdout.write(data) 

sys.stdout = Tee() 

Mi (roto) intento de llevar todo esto junto a continuación, fue crear un objeto LoggedConsole, y pasarlo Tee en los locales.

console = LoggedConsole(locals={sys.stdout:LoggedExec()}) 
console.interact() 

(yo no he pasado los locales antes, por eso lo estoy haciendo mal aquí, pero no recibo un error.)

De todas formas, esto abrirá una nueva consola interactiva, y registrará (después de cerrar) todas las entradas y errores, pero no la salida. He estado golpeando mi cabeza contra esto por un tiempo, y siento que estoy cerca, pero tal vez ni siquiera.

Además, ¿hay alguna manera de que todo esto ocurra durante la sesión? Actualmente, todo el registro tiene lugar una vez que se cierra la sesión.

Gracias por su tiempo, disculpe el muro de texto.

editar: Me gustaría poder lograr esto en el intérprete estándar de Python con fines de portabilidad.

edit2: Jaime's snippet funciona muy bien para registrar todo lo que necesito. De todos modos, ¿puedo hacerlo en tiempo real, en lugar de esperar a que la sesión se cierre?

edit3: Lo entendí :). La final, fragmento de trabajo:

import code 
import sys 

class Tee(object): 
    def __init__(self, log_fname, mode='a'): 
    self.log = open(log_fname, mode) 

    def __del__(self): 
    # Restore sin, so, se 
    sys.stdout = sys.__stdout__ 
    sys.stdir = sys.__stdin__ 
    sys.stderr = sys.__stderr__ 
    self.log.close() 

    def write(self, data): 
    self.log.write(data) 
    self.log.flush() 
    sys.__stdout__.write(data) 
    sys.__stdout__.flush() 

    def readline(self): 
    s = sys.__stdin__.readline() 
    sys.__stdin__.flush() 
    self.log.write(s) 
    self.log.flush() 
    return s 

    def flush(foo): 
    return 

sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w') 

console = code.InteractiveConsole() 
console.interact() 
+0

BTW no estoy seguro de cuál es su caso de uso, pero 'ipython notebook' es una gran adición a un flujo de trabajo interactivo, en caso de que aún no lo haya visto. – Kos

Respuesta

7

sólo lo he probado esto en python2.7. No tengo 3 a mano.

import code 
import sys 

class Tee(object): 

    def __init__(self, log_fname, mode='a'): 
    self.log = open(log_fname, mode) 

    def __del__(self): 
    # Restore sin, so, se 
    sys.stdout = sys.__stdout__ 
    sys.stdir = sys.__stdin__ 
    sys.stderr = sys.__stderr__ 
    self.log.close() 

    def write(self, data): 
    self.log.write(data) 
    sys.__stdout__.write(data) 

    def readline(self): 
    s = sys.__stdin__.readline() 
    self.log.write(s) 
    return s 

# Tie the ins and outs to Tee. 
sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w') 

console = code.InteractiveConsole() 
console.interact() 
+0

Esto funciona muy bien. ¿Tienes alguna idea de cómo puedo hacer que inicie sesión en tiempo real? es decir, ¿no esperar hasta que la sesión se haya cerrado para escribir? Leí en alguna parte que una llamada a 'sys.stdout.flush()', etc, lo haría, pero estoy un poco inseguro de cómo implementarlo. ¡Gracias por su ayuda hasta ahora! –

+1

Lo descubrí. Necesita llamadas a 'flush()' para el archivo de registro y para los objetos stdout/in. ¡Gracias por empujarme en la dirección correcta! –

+0

Me alegro de que te haya ayudado. Solo debería necesitar vaciar el registro. No hay razón para eliminar stdout/stderr. Recuerde, el registro es lo único que realmente está escribiendo en el archivo, por lo que enjuagarlo debería ser suficiente. – jaime

3

Ver this Virtualenv article por Doug Hellmann, que muestra cómo iniciar una sesión de una sesión iPython:

Si se siente cómodo trabajando en el modo interactivo de esta manera , pero desea registrar lo que hace para referencias futuras después de cerrar su sesión, puede usar la función de registro de IPython para escribir la sesión en un archivo. Para activar el registro, use el comando de control %logstart, como se ilustra en el Listado 5. El archivo de salida es un archivo fuente de Python, por lo que es fácil de limpiar y convertir en un módulo "real" cuando haya terminado de experimentar.

In [6]: %logstart 
Activating auto-logging. Current session state plus future input saved. 
Filename  : ipython_log.py 
Mode   : rotate 
Output logging : False 
Raw input log : False 
Timestamping : False 
State   : active 

In [7]: a = 5 

In [8]: b = 6 

In [9]: c = a * b 

In [10]: c 

Out[10]: 30 

In [11]: d = [ a, b, c] 

In [12]: d 

Out[12]: [5, 6, 30] 

In [13]: %logstop 
+0

¡Gracias por la referencia! Sin embargo, me gustaría hacer que esto funcione en el intérprete estándar. Mi objetivo aquí es crear algo así como un tutorial interactivo para los fundamentos de Python (y para enseñarme a lo largo del camino), y me gustaría que sea portátil para el beneficio de amigos que puedan usarlo. –

2

Usted puede simplemente utilizar la secuencia de comandos de Unix, intente:

script -a filename.txt 
python 
>> print("hi") 
hi 
>> exit() 
exit 

filename.txt grabará todo lo que hizo en ese período de sesiones, que se verá algo como esto:

Script started on Sat Dec 14 11:18:41 2013 
python 
>> print('hi') 
hi 
>> exit() 
exit 

Script done on Sat Dec 14 11:18:59 2013 
0

Puedes probar y usar mi herramienta de registro. Todavía no es perfecto, pero resolvió mi problema, que parece similar a tu.

https://github.com/hholst80/loginteractive

Funciona mediante el uso LD_PRELOAD a stdin.txt tubería (o $ STDIN) a la salida estándar. Funciona para python y octava, aunque todavía no lo he probado que mucho.

Cuestiones relacionadas