es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo tener una línea de entrada cómoda (por ejemplo, al estilo del GNU-readline) en una tarea de asyncio?

Tengo un programa asyncio con dos tareas:

  • la tarea 1 realiza cierto trabajo
  • la tarea 2 proporciona una interfaz de línea de comandos (CLI); lee comandos escritos por el usuario y los envía a la tarea 1 para que los procese

La CLI es básicamente un bucle que lee líneas de un flujo asyncio conectado a la entrada estándar.

Funciona, pero no es muy cómodo. El problema es que la línea de entrada no ofrece comandos de edición, excepto [BACKSPACE ctrl-H] y [ctrl-U], que se procesan a nivel de terminal de Linux, no en el programa. Quiero al menos flechas [LEFT] y [RIGHT] y [DEL].

Intenté usar la función interna input() con readline importado, lo que me da una edición cómoda, pero debe ejecutarse en un thread separado porque es bloqueante (loop.run_in_executor).

Ahora el problema es el manejo de [ctrl-C] (KeyboardInterrupt). Las tareas se cancelan, pero input() en su propio thread todavía espera la tecla [ENTER]. Solo después de presionar [ENTER], la aplicación se detiene. Esto es tan confuso y es un “bloqueador de errores” para este enfoque. Desafortunadamente, no es posible matar un thread, así que no puedo hacer que una pulsación de tecla [ctrl-C] termine el programa de forma normal.

¿Tienes alguna idea de cómo resolver el problema con input() o conoces una forma alternativa de habilitar la edición básica de la línea de entrada en una tarea asyncio?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Para habilitar la edición básica de líneas de entrada en una tarea asyncio, una solución es utilizar la biblioteca prompt_toolkit, que proporciona una manera de construir interfaces de línea de comandos con capacidades de edición avanzadas.

    Esta biblioteca se integra bien con asyncio y proporciona una implementación de ciclo de eventos asyncio. Con prompt_toolkit, puede obtener características avanzadas de edición, como autocompletado, resaltado de sintaxis, entrada de varias líneas, historial y deshacer-rehacer.

    Aquí hay un ejemplo de cómo puede usar prompt_toolkit para habilitar la edición básica de líneas de entrada:

    from prompt_toolkit import prompt_async, PromptSession
    
    async def cli(loop):
        ps = PromptSession()
        while True:
            try:
                # use `prompt_async` to read from input with asyncio support
                # this will give basic editing capabilities such as Left/Right arrows and Delete
                command = await prompt_async(ps.prompt)
    
                # process the command here
    
            except KeyboardInterrupt:
                # handle Ctrl-C here
                break
    
    loop.run_until_complete(cli(loop))
    

    En este ejemplo, creamos un objeto PromptSession que podemos usar para leer la entrada del usuario con prompt_async. La función prompt_async nos permite leer la entrada de forma asíncrona y proporciona una corrutina que podemos esperar.

    prompt_async nos proporciona capacidades básicas de edición, como flechas Izquierda/Derecha y Borrar.

    Con este enfoque, también puede manejar KeyboardInterrupt y detener el ciclo de manera ordenada.

    ¡Espero que esto ayude!

Comments are closed.