2009-01-12 8 views
12

Tengo una aplicación basada en Python que puede aceptar algunos comandos en un simple read-eval-print-loop. Estoy usando raw_input('> ') para obtener la entrada. En los sistemas basados ​​en Unix, también import readline para hacer que las cosas se comporten un poco mejor. Todo esto está funcionando bien.¿Cómo implementar un REPL de Python que maneje bien la salida asíncrona?

El problema es que hay eventos asíncronos que entran, y me gustaría imprimir la salida tan pronto como suceden. Desafortunadamente, esto hace que las cosas se vean feas. La cadena ">" no aparece de nuevo después de la salida, y si el usuario está a la mitad de escribir algo, corta el texto a la mitad. Probablemente debería volver a dibujar el texto en progreso del usuario después de imprimir algo.

Parece que debe ser un problema resuelto. ¿Cuál es la forma correcta de hacer esto?

También tenga en cuenta que algunos de mis usuarios están basados ​​en Windows.

TIA

Editar: La respuesta aceptada funciona bajo plataformas Unixy (cuando el módulo readline está disponible), pero si alguien sabe cómo hacer este trabajo bajo Windows, que sería muy apreciada!

Respuesta

8

Tal vez algo como esto hará el truco:

#!/usr/bin/env python2.6 

from __future__ import print_function 

import readline 
import threading 

PROMPT = '> ' 

def interrupt(): 
    print() # Don't want to end up on the same line the user is typing on. 
    print('Interrupting cow -- moo!') 
    print(PROMPT, readline.get_line_buffer(), sep='', end='') 

def cli(): 
    while True: 
     cli = str(raw_input(PROMPT)) 

if __name__ == '__main__': 
    threading.Thread(target=cli).start() 
    threading.Timer(2, interrupt).start() 

No creo que la entrada estándar es seguro para subprocesos, por lo que puede terminar perdiendo caracteres al hilo de interrupción (que el usuario tendrá que vuelva a escribir al final de interrupt). Exageré la cantidad de tiempo de interrupt con la llamada time.sleep. La llamada readline.get_line_buffer no mostrará los caracteres que se pierden, por lo que todo está bien.

Tenga en cuenta que stdout en sí no es seguro para subprocesos, por lo que si tiene múltiples subprocesos de ejecución de interrupción, esto todavía puede terminar en bruto.

+0

Gracias, readline.get_line_buffer() es un buen comienzo. Si alguien tiene algún consejo sobre cómo hacer que esto funcione en Windows (que no tiene un módulo de lectura), házmelo saber. – andy

+0

¿Funciona en Cygwin, tal vez? – cdleary

-1

Es una especie de falta de respuesta, pero me gustaría ver el código IPython para ver cómo lo están haciendo.

-1

Creo que tienes 2 opciones básicas:

  1. sincronizar su salida del bloque (es decir, hasta que regresa)
  2. separar su entrada y su salida (asíncrona), tal vez en dos columnas separadas.
5

¿Por qué está escribiendo su propio REPL usando raw_input()? ¿Has mirado la clase cmd.Cmd? Edit: Acabo de encontrar la biblioteca sclapp, que también puede ser útil.

Nota: la clase cmd.Cmd (y sclapp) puede o no apoyar directamente su objetivo original; es posible que deba subclasificarlo y modificarlo según sea necesario para proporcionar esa función.

+0

cmd.Cmd se ve bastante impresionante y probablemente debería comenzar a usarlo. Sin embargo, no parece lograr mi objetivo original, ¿algún consejo? – andy

+3

sclapp parece estar extinto. El enlace proporcionado no funcionó y no encontré su nuevo hogar. –

0

mira en el módulo de código, te permite crear objetos para interpretar código python también (plug desvergonzado) https://github.com/iridium172/PyTerm te permite crear programas interactivos de línea de comandos que manejan entrada de teclado sin procesar (como^C provocará una interrupción del teclado).

2

plazo esto:

python -m twisted.conch.stdio 

que obtendrá un bonito, color, asíncrono REPL, sin utilizar hilos. Mientras escribe en el aviso, el bucle de evento se está ejecutando.

Cuestiones relacionadas