pty — Утиліти псевдотерміналу

Вихідний код: Lib/pty.py


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

Робота з псевдотерміналом сильно залежить від платформи. Цей код в основному тестується на Linux, FreeBSD і macOS (передбачається, що він працює на інших платформах POSIX, але не був ретельно протестований).

Модуль pty визначає такі функції:

pty.fork()

Вилка. Підключіть керуючий термінал дитини до псевдотерміналу. Повернене значення: (pid, fd). Зверніть увагу, що дитина отримує pid 0, а fd є недійсним. Значенням, що повертає батьківський елемент, є pid дочірнього, а fd — це дескриптор файлу, підключений до керуючого терміналу дочірнього (а також до стандартного введення та виведення дочірнього).

Попередження

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()

Відкрийте нову пару псевдотерміналів, використовуючи os.openpty(), якщо можливо, або код емуляції для загальних систем Unix. Повертає пару файлових дескрипторів (master, slave) для головного та підлеглого кінця відповідно.

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

Створіть процес і підключіть його керуючий термінал до стандартного io поточного процесу. Це часто використовується, щоб збентежити програми, які наполягають на читанні з керуючого терміналу. Очікується, що процес, породжений за 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() дочірнього процесу.

os.waitstatus_to_exitcode() can be used to convert the exit status into an exit code.

Викликає подію аудиту 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)