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 obtient0
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.
Return the exit status value from
os.waitpid()
on the child process.waitstatus_to_exitcode()
can be used to convert the exit status into an exit code.Raises an auditing event
pty.spawn
with argumentargv
.Modifié dans la version 3.4:
spawn()
renvoie maintenant la valeur renvoyée paros.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)