rept - ¿Cómo implementar un REPL de Python que maneje muy bien la salida asíncrona?
rept li (6)
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 que las cosas se comporten un poco mejor. Todo esto está funcionando bien.
El problema es que están entrando eventos asíncronos, y me gustaría imprimir la salida tan pronto como sucedan. 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 en plataformas Unixy (cuando el módulo readline está disponible), pero si alguien sabe cómo hacer que esto funcione en Windows, sería muy apreciado.
Es una especie de falta de respuesta, pero miraría el código de IPython para ver cómo lo están haciendo.
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 stdin sea seguro para subprocesos, por lo que puede terminar perdiendo caracteres en el hilo de interrupción (que el usuario tendrá que volver a escribir al final de la interrupt
). time.sleep
la cantidad de tiempo de interrupt
con la llamada time.sleep
. La llamada a 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 aún puede parecer bruto.
Creo que tienes 2 opciones básicas:
- Sincronice su salida (es decir, bloquee hasta que vuelva)
- Separe su entrada y su salida (asincronous), tal vez en dos columnas separadas.
¿Por qué estás escribiendo tu propio REPL usando raw_input()
? ¿Has mirado la clase cmd.Cmd
? Editar: Acabo de encontrar la biblioteca sclapp , que también puede ser útil.
Nota: la clase cmd.Cmd
(y sclapp) puede o no respaldar directamente su objetivo original; es posible que deba subclasificarlo y modificarlo según sea necesario para proporcionar esa función.
mira en el módulo de código, te permite crear objetos para interpretar el código python también (plug desvergonzado) https://github.com/iridium172/PyTerm te permite crear programas de línea de comandos interactivos que manejan la entrada de teclado sin procesar (como ^ C levantará un KeyboardInterrupt).
ejecuta esto:
python -m twisted.conch.stdio
Obtendrás una REPL asincrónica agradable, coloreada, sin usar hilos . Mientras escribe en el aviso, el bucle de evento se está ejecutando.