"pty" --- Pseudo-terminal utilities
***********************************

**Código Fuente:** Lib/pty.py

======================================================================

El módulo "pty" define las operaciones para manejar el concepto de
pseudo-terminal: iniciar otro proceso para poder escribir y leer desde
su propia terminal mediante programación.

Availability: Unix.

El manejo de pseudo-terminales depende en gran medida de la
plataforma. Este código se prueba principalmente en Linux, FreeBSD y
macOS (se supone que funciona en otras plataformas POSIX, pero no se
ha probado a fondo).

El modulo "pty" define las siguientes funciones:

pty.fork()

   Bifurcación. Conectar en su propia terminal (terminal hijo) una
   pseudo-terminal. El valor de retorno es "(pid, fd)". Tener en
   cuenta que la terminal hijo tiene como valor *pid* 0 y *fd* es
   *invalid*. El valor de retorno del padre es el *pid* del hijo, y
   *fd* es un descriptor de archivo conectado a la terminal hijo
   (también a la salida y entrada estándar de la terminal hijo)

   Advertencia:

     On macOS the use of this function is unsafe when mixed with using
     higher-level system APIs, and that includes using
     "urllib.request".

pty.openpty()

   Abre un nuevo par de pseudo-terminales, usando "os.openpty()", o
   código de emulación para sistemas genéricos de Unix. Retorna un par
   de descriptores de archivo "(master, slave)", para el *master* y el
   *slave* respectivamente.

pty.spawn(argv[, master_read[, stdin_read]])

   Genera un proceso conectado a su terminal con el io estándar del
   proceso actual. Esto se usa a frecuentemente para confundir
   programas que insisten en leer desde la terminal de control. Se
   espera que el proceso generado detrás de pty sea finalizado y
   cuando lo haga *spawn* se retornará.

   Un bucle copia STDIN del proceso actual al hijo y los datos
   recibidos del niño a STDOUT del proceso actual. No se le indica al
   hijo si STDIN del proceso actual se cierra.

   A las funciones *master_read* y *stdin_read* se les pasa un
   descriptor de archivo del cual deben leer, y siempre deben retornar
   una cadena de bytes. Para forzar el retorno de spawn antes de que
   el proceso hijo salga, se debe retornar un arreglo de bytes vacía
   para señalar el final del archivo.

   La implementación predeterminada para ambas funciones retornará
   hasta 1024 bytes cada vez que se llamen. El dato retornado de
   *master_read* se pasa al descriptor de archivo maestro para leer la
   salida del proceso hijo, y *stdin_read* pasa el descriptor de
   archivo 0, para leer desde la entrada del proceso padre.

   Retornando una cadena de bytes vacía de cualquier llamado es
   interpretado como una condición de fin de archivo (EOF), y el
   llamado no se realizará después de eso. Si *stdin_read* retorna EOF
   la terminal de control ya no puede comunicarse con el proceso padre
   o el proceso hijo. A menos que el proceso hijo se cierre sin
   ninguna entrada *spawn* se repetirá para siempre. Si *master_read*
   retorna EOF se produce el mismo comportamiento (al menos en Linux)

   Retorna el valor del estado de salida de "os.waitpid()" en el
   proceso hijo.

   "os.waitstatus_to_exitcode()" se puede utilizar para convertir el
   estado de salida en un código de salida.

   Lanza un evento de auditoria "pty.spawn"  con el argumento "argv".

   Distinto en la versión 3.4: "spawn()" ahora retorna el valor de
   estado de  "os.waitpid()" para los procesos hijos.


Ejemplo
=======

El siguiente programa actúa como el comando de Unix *script(1)*,
usando una pseudo-terminal para registrar todas las entradas y salidas
de una sesión en "typescript".

   import argparse
   import os
   import pty
   import sys
   import time

   parser = argparse.ArgumentParser()
   parser.add_argument('-a', dest='append', action='store_true')
   parser.add_argument('-p', dest='use_python', action='store_true')
   parser.add_argument('filename', nargs='?', default='typescript')
   options = parser.parse_args()

   shell = sys.executable if options.use_python else os.environ.get('SHELL', 'sh')
   filename = options.filename
   mode = 'ab' if options.append else 'wb'

   with open(filename, mode) as script:
       def read(fd):
           data = os.read(fd, 1024)
           script.write(data)
           return data

       print('Script started, file is', filename)
       script.write(('Script started on %s\n' % time.asctime()).encode())

       pty.spawn(shell, read)

       script.write(('Script done on %s\n' % time.asctime()).encode())
       print('Script done, file is', filename)
