UglierPTY is a very functional proof-of-concept (POC) application created to construct a fully functional SSH Terminal Widget using PyQt6. This POC is inspired by its sister project, UglyPTY, a full-featured SSH client that utilizes xterm.js. The aim is to offer a similar, if not superior, feature set without relying on browser technologies or JavaScript, resulting in a more streamlined and resource-efficient solution.
This is a work in progress, but feel free to give it a try! REPO: https://github.com/scottpeterman/UglierPTY
If your interested in the PyQt6/XTerm.js version of this application take a look here: https://github.com/scottpeterman/UglyPTY
- Fully functional SSH terminal built with PyQt6
- Credentials manager for easy login
- Portable session files in YAML (Compatible with UglyPTY)
- Terminal history and screen ratio control via pyte
- Terminal screen render via QPaint
- Modular design for easy embedding into other PyQt6 projects
- Pure Python - Free of Web technology (no xterm.js)
- Python 3.x
- PyQt6
- Paramiko
- pyte
- SQLAlchemy
- PyYaml
Here are some snapshots of Uglier in action:
-
Clone the repository:
git clone https://github.com/scottpeterman/UglierPTY
-
Navigate into the project directory:
cd UglierPTY
-
Install the required Python packages:
pip install -r requirements.txt
The primary entry point for this POC is the uglierpty.py
script. To launch the application:
If you cloned the repo
python run_test.py
If you installed via PIP
python -m uglierpty
or
pythonw -m uglierpty
<title>SSH Terminal Flow</title>
+--------------------+ +-------------------+ +-------------------+ +------------+ +------------------+ | SSHTerminalWidget | | SSHLib Class | | Communication | | pyte | | Remote SSH Host | | | | | | | | | | | | keyPressEvent() |------>| write(data) |------>| sendDataToSSH() |------>| |------>| Shell Process | | | | | | | | | | | +--------------------+ +-------------------+ +-------------------+ +------------+ +------------------+ ^ ^ ^ ^ | | | | | | | | | | | | | | | | +--------------------+ +-------------------+ +-------------------+ +------------+ +------------------+ | SSHTerminalWidget | | SSHLib Class | | Communication | | pyte | | Remote SSH Host | | | | | | | | | | | | paintEvent() |<------| read() |<------| receiveDataFromSSH() |<------| feed() |<------| Shell Process | | | | | | | | stream.attach(screen) | | | +--------------------+ +-------------------+ +-------------------+ +------------+ +------------------+
- Keystroke in SSHTerminalWidget: The
keyPressEvent()
function captures the keystroke and sends it to theSSHLib
class viawrite(data)
. - Sending to SSH Channel: The
write()
method sends the data through an SSH channel, probably utilizingparamiko.SSHClient
. This is done inCommunication.sendDataToSSH()
. - SSH to Remote Host: The keystroke reaches the shell process running on the remote SSH host.
- Remote Host to pyte: Once the shell process echoes the output, it's read by
Communication.receiveDataFromSSH()
and fed to pyte'sStream
object viafeed()
inSSHLib.read()
. - pyte to GUI: The
Stream
object updates theScreen
object, which theSSHTerminalWidget.paintEvent()
method uses to draw on the GUI, completing the round trip.