cómo enviar tab-key a la entrada estándar de Python Subprocess

Antecedentes: tengo un subproceso Python que se conecta a una aplicación similar a una shell, que usa la biblioteca readline para manejar la entrada, y esa aplicación tiene una rutina de TAB completa para la entrada de comandos, como bash. El proceso hijo se genera, así:

def get_cli_subprocess_handle(): return subprocess.Popen( '/bin/myshell', shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) 

Todo funciona muy bien, excepto tab-complete. Cada vez que mi progtwig Python pasa el carácter de tabulación, '\t' al subproceso, obtengo 5 espacios en el STDIN, en lugar de activar la rutina de tabulación completa de la biblioteca readline. 🙁

Pregunta: ¿Qué puedo enviar al STDIN del subproceso para activar la función de tabulación completa del niño? Quizás se pregunte de otra manera: ¿Cómo envío la tecla TAB en lugar del carácter TAB, si eso es posible?

Relacionado pero sin respuesta y descarrilado:

completar la pestaña de disparo para el proceso por lotes de Python construido alrededor de readline

La aplicación tipo shell probablemente esté diferenciando entre un terminal que está conectado a una entrada estándar y una tubería que está conectada a él. Muchas utilidades de Unix hacen precisamente eso para optimizar su almacenamiento en búfer (línea contra bloque) y es probable que las utilidades de tipo shell deshabiliten las funciones de finalización de comandos en la entrada por lotes (es decir, PIPE) para evitar resultados inesperados. La finalización del comando es realmente una característica interactiva que requiere una entrada de terminal.

Revise el módulo pty e intente usar un par maestro / esclavo como la tubería para su subproceso.

Realmente no existe tal cosa como enviar una clave de tabulación a una tubería. Una tubería solo puede aceptar cadenas de bits, y si el carácter de tabulación no lo hace, puede que no haya una solución.

Hay un proyecto que hace algo similar llamado pexpect . Solo mirando su código interact() , no veo nada obvio que lo haga funcionar y el suyo no. Dado que, la explicación más probable es que pexpect realmente hace algún trabajo para parecer un pseudo-terminal. ¿Quizás podrías incorporar su código para eso?

Basado en la respuesta de isedev , modifiqué mi código de la siguiente manera:

 import os, pty def get_cli_subprocess_handle(): masterPTY, slaveTTY = pty.openpty() return masterPTY, slaveTTY, subprocess.Popen( '/bin/myshell', shell=False, stdin=slaveTTY, stdout=slaveTTY, stderr=slaveTTY, ) 

Usando esta tupla devuelta, pude realizar select.select([masterPTY],[],[]) y os.read(masterPTY, 1024) según sea necesario, y escribí al master-pty con una función que es muy similar a un método privado en la fuente del módulo pty:

 def write_all(masterPTY, data): """Successively write all of data into a file-descriptor.""" while data: chars_written = os.write(masterPTY, data) data = data[chars_written:] return data 

Gracias a todos por las buenas soluciones. Espero que este ejemplo ayude a alguien más. 🙂