¿Cómo registrar todo lo que ocurre en una sesión de shell interactivo de Python?

Me gustaría tener acceso en tiempo real a la entrada y al error del intérprete y a la salida estándar. Preferiblemente, esta información se escribiría en un archivo, de modo que pueda sondear los cambios del archivo después de que se haya ingresado cada comando del intérprete. Por ejemplo, dada una sesión de intérprete:

>>> 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 activar eventos interactivos durante la sesión.

Lo que he aprendido hasta ahora tratando de lograr esto:

El módulo de code de Python me permite crear un objeto InteractiveConsole , el método raw_input del cual puedo redefinir para iniciar sesión en un archivo, de esta manera:

 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 método de write incorporado para registrar errores, que puedo redefinir para:

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

También he aprendido que el siguiente fragmento de código registrará todas las salidas estándar:

 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) bash de juntar todo esto fue crear un objeto LoggedConsole y pasarlo a los locales.

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

(No he pasado a los locales antes, así que quizás lo estoy haciendo incorrectamente aquí, pero no recibo un error).

De todos modos, esto abrirá una nueva consola interactiva y registrará (después de cerrar) todas las entradas y errores, pero no la salida. Me he estado golpeando la cabeza contra esto durante 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 se lleva a cabo una vez que se cierra la sesión.

Gracias por su tiempo, perdón por la pared de texto.

edición: me gustaría poder lograr esto en el intérprete de Python estándar para propósitos de portabilidad.

edit2: el fragmento de Jaime funciona muy bien para registrar todo lo que necesito. Sin embargo, ¿de qué manera puedo hacerlo en tiempo real, en lugar de esperar a que se cierre la sesión?

edit3: Lo descubrí :). El fragmento final, 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() 

Solo he probado esto en python2.7. No tengo 3 a la 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() 

Eche un vistazo a IPython (no lo he usado yo mismo). Aquí hay una sección en los documentos que puede ser de particular interés: http://ipython.org/ipython-doc/dev/interactive/reference.html#session-logging-and-restring

Vea este artículo de Virtualenv por Doug Hellmann, que muestra cómo registrar una sesión de iPython :

Si se siente cómodo trabajando en el indicador interactivo de esta manera, pero desea grabar lo que hace para futuras consultas 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 convertirlo 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 

Simplemente puede usar el comando de script de Unix, intente:

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

filename.txt registrará todo lo que hiciste en esa sesión, se verá así:

 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 

Puedes probar y usar mi herramienta de registro. Aún no es perfecto, pero resolvió mi problema, que parece similar al tuyo.

https://github.com/hholst80/loginteractive

Funciona utilizando LD_PRELOAD para canalizar stdin.txt (o $ STDIN) a stdout. Funciona para python y octava, aunque todavía no lo he probado mucho.