pty — Утилиты для работы с псевдотерминалом
Исходный код: Lib/pty.py
Модуль pty определяет операции для работы с концепцией псевдотерминала: запуск другого процесса и возможность программно записывать данные в его управляющий терминал и считывать их из него.
Доступность: Unix.
Работа с псевдотерминалами во многом зависит от платформы. Этот код в основном тестировался в Linux, FreeBSD и macOS (предполагается, что он будет работать и на других POSIX-платформах, но это не было тщательно проверено).
Модуль pty определяет следующие функции:
-
pty.fork() -
Создаёт дочерний процесс. Подключает управляющий терминал дочернего процесса к псевдотерминалу. Возвращаемое значение —
(pid, fd). Обратите внимание, что дочерний процесс получает pid 0, а fd является недействительным. Родительский процесс получает в качестве возвращаемого значения pid дочернего процесса, а fd — файловый дескриптор, подключённый к управляющему терминалу дочернего процесса (а также к его стандартным потокам ввода и вывода).Предупреждение
В macOS использование этой функции небезопасно в сочетании с высокоуровневыми системными API, включая использование
urllib.request.
-
pty.openpty() -
Открывает новую пару псевдотерминалов, используя, если возможно,
os.openpty()или эмулирующий код для систем Unix общего назначения. Возвращает пару файловых дескрипторов(master, slave): сначала для главного, затем для ведомого конца.
-
pty.spawn(argv[, master_read[, stdin_read]]) -
Запускает процесс и подключает его управляющий терминал к стандартным потокам ввода-вывода текущего процесса. Это часто используется, чтобы обмануть программы, которые настаивают на чтении из управляющего терминала. Предполагается, что процесс, запущенный через pty, в конечном итоге завершится; после этого функция spawn вернёт управление.
В цикле данные из STDIN текущего процесса копируются в дочерний процесс, а полученные от дочернего процесса данные — в STDOUT текущего процесса. Если STDIN текущего процесса закрывается, дочерний процесс об этом не уведомляется.
Функциям master_read и stdin_read передаётся файловый дескриптор, из которого они должны считывать данные; они всегда должны возвращать байтовую строку. Чтобы функция spawn вернула управление до завершения дочернего процесса, следует вернуть пустой байтовый массив, сигнализирующий о конце файла.
Реализация этих функций по умолчанию считывает и возвращает до 1024 байт при каждом вызове. Функции обратного вызова master_read передаётся главный файловый дескриптор псевдотерминала для чтения вывода дочернего процесса, а функции stdin_read передаётся файловый дескриптор 0 для чтения стандартного ввода родительского процесса.
Возврат пустой байтовой строки из любой функции обратного вызова интерпретируется как условие конца файла (EOF), и после этого эта функция обратного вызова вызываться не будет. Если stdin_read сообщает об EOF, управляющий терминал больше не может обмениваться данными с родительским ИЛИ дочерним процессом. Если дочерний процесс не завершится без ввода, функция spawn будет бесконечно выполнять цикл. Если об EOF сообщает master_read, происходит то же самое (по крайней мере, в Linux).
Возвращает значение статуса завершения дочернего процесса, полученное от
os.waitpid().Для преобразования статуса завершения в код завершения можно использовать
os.waitstatus_to_exitcode().Вызывает событие аудита
pty.spawnс аргументомargv.Изменено в версии 3.4:
spawn()теперь возвращает значение статуса дочернего процесса, полученное отos.waitpid().
Пример
Следующая программа работает подобно команде Unix script(1), используя псевдотерминал для записи всего ввода и вывода терминального сеанса в «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)
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/pty.html