"pty" — Outils de manipulation de pseudo-terminaux
**************************************************

**Code source :** Lib/pty.py

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

Le module "pty" expose des fonctions de manipulation de pseudo-
terminaux, il permet d'écrire un programme capable de démarrer un
autre processus, d'écrire et de lire depuis son terminal.

La gestion de pseudo-terminaux étant très dépendante de la plateforme,
ce code ne gère que Linux. (Code supposé fonctionner sur d'autres
plateformes, mais sans avoir été testé).

Le module "pty" expose les fonctions suivantes :

pty.fork()

   *Fork*. Connecte le terminal contrôlé par le fils à un pseudo-
   terminal. La valeur renvoyée est "(pid, fd)". Notez que le fils
   obtient "0" comme *pid* et un *fd* non valide. Le parent obtient le
   *pid* du fils, et *fd* un descripteur de fichier connecté à un
   terminal contrôlé par le fils (et donc à l'entrée et la sortie
   standard du fils).

pty.openpty()

   Ouvre une nouvelle paire de pseudo-terminaux, en utilisant si
   possible "os.openpty()", ou du code émulant la fonctionnalité pour
   des systèmes *Unix* génériques. Renvoie une paire de descripteurs
   de fichier "(master, slave)", pour le maître et pour l'esclave
   respectivement.

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

   Crée un nouveau processus et connecte son terminal aux
   entrées/sorties standard du processus courant. Cette stratégie est
   typiquement utilisée pour les programmes qui veulent lire depuis
   leur propre terminal. Le processus créé utilisant le *pty* est
   supposé se terminer et, quand il le fera, l'appel de *spawn*
   terminera.

   Les fonctions *master_read* et *stdin_read* reçoivent un
   descripteur de fichier qu'elles doivent lire, et elles doivent
   toujours renvoyer une chaîne d'octets. Afin de forcer le *spawn* à
   faire un renvoi avant que le processus enfant ne se termine, une
   exception "OSError" doit être levée.

   L'implémentation par défaut pour les deux fonctions lit et renvoie
   jusqu'à 1024 octets à chaque appel de la fonction. La fonction de
   rappel *master_read* reçoit le descripteur de fichier du pseudo-
   terminal maître pour lire la sortie du processus enfant, et
   *stdin_read* reçoit le descripteur de fichier 0, pour lire l'entrée
   standard du processus parent.

   Le renvoi d'une chaîne d'octets vide à partir de l'un ou l'autre
   des rappels est interprété comme une condition de fin de fichier
   (EOF), et ce rappel ne sera pas appelé après cela. Si *stdin_read*
   signale EOF, le terminal de contrôle ne peut plus communiquer avec
   le processus parent OU le processus enfant. À moins que le
   processus enfant ne quitte sans aucune entrée, *spawn* sera lancé
   dans une boucle infinie. Si *master_read* indique la fin de
   fichier, on aura le même comportement (sur Linux au moins).

   Si les deux fonctions de rappel indiquent la fin de fichier
   (*EOF*), alors *spawn* ne fera probablement jamais de renvoi, à
   moins que *select* ne lance une erreur sur votre plateforme lors du
   passage de trois listes vides. Il s'agit d'un bogue, renseigné dans
   https://bugs.python.org/issue26228.

   Raises an auditing event "pty.spawn" with argument "argv".

   Modifié dans la version 3.4: "spawn()" renvoie maintenant la valeur
   renvoyée par "os.waitpid()" sur le processus fils.


Exemple
=======

Le programme suivant se comporte comme la commande Unix *script(1)*,
utilisant un pseudo-terminal pour enregistrer toutes les entrées et
sorties d'une session dans un fichier *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)
