python library & utility to intercepting and processing i/o of CLI/TUI programs using PTYs.
What are pseudo-terminals (PTY)?
It's a UNIX specific (Windows also supports it) form of interprocess
communication. Think about it as channel which could provide bidirectional flow
of data between two programs. It also provides child process with some terminal
services (size, list of supported colors, etc).
Why is that even needed?
It's needed for automatization or situations when you need to run console
applications in the environments without a terminal.
Why on earth even run terminal applications without a terminal!?
For example: when you connected to the server via SSH - the server isn't
running a terminal, it just sends data through the internet to the client.
But some programs on the server expects to be executed in the terminal, to know
how exactly to render data (e.g. vim, nano), so SSH server provides
pseudo-terminal for them.
It seems like a very niche use case for that, are any other usages for PTYs?
Interesting fact: I didn't use above the term terminal emulator and thats not
for brevity.
PTYs are used when you don't have a real physical terminal device like VT-100.
When you are opening terminal emulator such as Konsole, under the hood there
is runned pseudo-terminal.
So the use cases are following:
- terminal emulators (
xterm,konsole,yakuake) - ssh servers.
- terminal multiplexers (
GNU screen,tmux,zellij). - running terminal applications in environments without controlling terminal e.g. in child processes.
- i/o processing, e.g. keylogging like
GNU scriptor automation tasks asexpect,pyexpect.
The latter two use cases are the main focus for the pyntercept.
┌─────────────┐ ┌───────────────┐
│ src (stdin) │ │ dest (stdout) │
└─────────────┘ └───────────────┘
(1) │ ^(6)
│ ┌─────────────────┐───┘ (0)┌────────────────┐
└──>│ parent process │──────────────>│ child process │
└─────────────────┘ └────────────────┘
(2)│ ^(5) (4)│ ^(3)
┌─── v ── │ ───────────────────────── v ────── │ ────────┐
│ ┌─────────────┐<─────────────────┌─────────────┐ │
│ │ parent's fd │ │ child fd │ │
│ └─────────────┘─────────────────>└─────────────┘ │
│ ^ │
│ acts like a real terminal for the │
│ child process │
│ │
└──────────────Pseudo terminal (PTY)─────────────────────┘
- parent process first allocates resources for processes interaction and then runs child process with specified arguments and behaving as proxy object for enteraction with child process.
- parent process receives input from source (by default stdin).
- then parent could do any transformations to it and even could decide to send it to the child process or not.
- child process reads data from step (1) as its
stdin. - child process could generate some output and writes it into the child terminal.
- parent process reads output sent by child process. Like in step 2, parent process can transform output data and conditionally send it to the destination as step (6).
pipx install pynterceptpip install pyntercept# if you want rich renderer which also will install pyntercept[pyte]
pip install pyntercept[rich]
pip install pyntercept[pyte] # if you want pyte (Buffered) rendereravailable optional dependencies are:
- rich
- pyte
- curses support of 256, true colors.
- fix rendering with
richpython library. - support of Don Libes'
expectlanguage - [DONE] optional dependencies
pyntercept[pyte],pyntercept[rich], etc. - filters, different rendering stages and strategies to give an ability to pass data into wider spectre of the programs.
- wider support of external libraries, programs and use cases.
- [DONE] accumulate differences (like cursor movement or character changes) to optimize rendering and support more environments and use cases.
- support of Windows and other operating systems.
- add built-in ability to specify areas of the terminal where to render data.