Документация Python неофициальный перевод
Содержание страницы

pty – Утилиты псевдотерминаловpty – Pseudo-terminal utilities

Исходный код: Lib/pty.py


Модуль pty определяет операции для работы с концепцией псевдотерминала: запуск другого процесса и возможность программно записывать и читать из его управляющего терминала.

Работа с псевдотерминалами сильно зависит от платформы. Данный код в основном тестировался на Linux, FreeBSD и macOS (предполагается, что он работает на других POSIX-платформах, но тщательного тестирования не проводилось).

Модуль pty определяет следующие функции:

pty.fork()

Создаёт процесс. Подключает управляющий терминал дочернего процесса к псевдотерминалу. Возвращаемое значение – (pid, fd). Обратите внимание, что дочерний процесс получает pid равным 0, а fd является недействительным. Родительский процесс возвращает pid дочернего процесса, а fd – это файловый дескриптор, подключённый к управляющему терминалу дочернего процесса (а также к его стандартному вводу и выводу).

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 будет циклически ожидать вечно. Если master_read сигнализирует EOF, поведение будет таким же (по крайней мере, в Linux).

Возвращает значение статуса выхода от os.waitpid() для дочернего процесса.

waitstatus_to_exitcode() можно использовать для преобразования статуса выхода в код возврата.

Вызывает событие аудита pty.spawn с аргументом argv.

Изменено в версии 3.4: spawn() теперь возвращает значение статуса от os.waitpid() для дочернего процесса.

ПримерExample

Следующая программа действует как команда 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)