A library for building terminal applications with NiceGUI and rich terminal features.
Project description
NiceTerminal: A NiceGUI xterm.js Control
This WIP project provides an xterm.js based terminal component for your NiceGUI apps, running on both Linux and Windows. It allows you to embed fully interactive terminals (local shells, serial connections, or anything else) within your NiceGUI UI.
Disclaimer: This is not an official NiceGUI project. Use it at your own risk, especially when enabling shell or device access.
Features
- NiceGUI Integration: Easily add a terminal component inside your NiceGUI UI.
- Local Shell Support: Provides a local shell out of the box on Linux and Windows (via
pywinptyon Windows). - Serial/Custom Support: Extend the base
Interfaceclass to communicate with any data source, such as serial devices, remote servers, or custom processes. - Concurrent Access: Multiple terminals or multiple users are supported.
- Persistent State: Caches screen data, so refreshing doesn’t necessarily lose session output.
- Optional Authentication: The
nicetermCLI supports authentication or no-auth modes. - Isolation Levels: Control whether terminals are shared globally, per user, or per browser tab.
Installation
Library only:
pip install niceterminal
Library + CLI (installs the niceterm command):
pip install niceterminal[cli]
Note: The CLI offers easy web-based shell access, which can be a security concern. Enable it only if you understand the risks.
Quick Start
A minimal example to embed a shell terminal in a NiceGUI page:
from nicegui import ui
from niceterminal.xterm import ShellXTerm
# Create a full-page terminal that opens your default shell.
ShellXTerm().classes("w-full h-full")
ui.run()
Open your app in the browser. You’ll see a page hosting an interactive shell.
Library Overview
niceterminal is built around two key abstractions:
- XTerm – A NiceGUI element based on xterm.js, rendering an interactive terminal in the browser.
- Interface – An abstract base class specifying how terminal input/output is processed on the Python side.
XTerm Class
from niceterminal.xterm import XTerm
Purpose:
- Renders an xterm.js terminal in NiceGUI.
- Handles sending data to and receiving data from a backend (shell, serial port, custom service, etc.).
Key Parameters / Methods:
__init__(self, config: TerminalConfig, interface:Interface=None, on_change: Callable, on_close: Callable, **kwargs)interface: A subclass ofInterfacethat manages I/O.
write(self, data: bytes)- Called by the attached interface to send output to the terminal.
set_cursor_location(self, row: int, col: int)- Manually position the cursor on the UI (not interface)
Example:
from niceterminal.interface.base import Interface, INTERFACE_STATE_STARTED, INTERFACE_STATE_INITIALIZED
from loguru import logger
from nicegui import ui
from niceterminal.xterm import XTerm
class EchoInterface(Interface):
async def write(self, data: bytes):
if data:
self.on_read_handle(data)
@logger.catch
async def launch_interface(self):
"""Starts the shell process asynchronously."""
if self.state != INTERFACE_STATE_INITIALIZED:
return
self.state = INTERFACE_STATE_STARTED
# Instantiate our custom interface for a specific echo device
echo_interface = EchoInterface()
echo_interface.start()
# Render in your NiceGUI app
ui.label("Echo Terminal")
# Create an XTerm bound to the echo interface
echo_terminal = XTerm(interface=echo_interface).classes("w-full h-full")
ui.run()
In this simplistic example, whatever the user types is immediately echoed back.
ShellXTerm Subclass
from niceterminal.xterm import ShellXTerm
Purpose:
- A convenience subclass that provides a local shell interface automatically (using
ptyon Linux orpywinptyon Windows).
Key Usage:
ShellXTerm().classes("w-full h-full")
- Spawns
bashon Linux orcmd.exeon Windows. - If you need a different shell (e.g.,
powershell), you can pass arguments directly to the underlying interface.
Interface Base Class
from niceterminal.interface import Interface
Purpose:
- Defines the core contract for reading/writing data between the browser-based terminal and a Python-driven data source.
Key Methods:
write(self, data: bytes) -> None- Invoked when the user types or sends data from the terminal.
on_read_handle(self, data: bytes) -> None- Sends data to be rendered in the terminal.
close(self) -> None- Close/cleanup the underlying connection or process.
is_closed(self) -> bool- Return True if the backend is closed or invalid.
Extend Interface to suit your needs (local shell, remote connections, serial devices, etc.).
Serial Port Example
Below is an example of using pyserial to connect a serial port to the terminal.
- Install pyserial:
pip install pyserial
- Create a custom interface that:
- Opens the serial port.
- Listens for incoming data (in a background thread).
- Forwards terminal input back to the serial device.
import threading
import serial
from niceterminal.interface.base import Interface, INTERFACE_STATE_STARTED, INTERFACE_STATE_INITIALIZED
from loguru import logger
from nicegui import ui
from niceterminal.xterm import XTerm
class SerialPortInterface(Interface):
def __init__(self, port="/dev/ttyUSB0", baudrate=115200, *args, **kwargs):
super().__init__(*args, **kwargs)
self.port = port
self._closed = False
self.baudrate = baudrate
self.ser = None
@logger.catch
async def launch_interface(self):
"""Starts the shell process asynchronously."""
if self.state != INTERFACE_STATE_INITIALIZED:
return
self.state = INTERFACE_STATE_STARTED
# Open the serial device
self.ser = serial.Serial(self.port, self.baudrate, timeout=0)
# Start a background thread to read from the serial port
self._read_thread = threading.Thread(target=self._read_loop, daemon=True)
self._read_thread.start()
def _read_loop(self):
while not self._closed:
data = self.ser.read(1024) # Non-blocking read
if data:
# Send any received data to the terminal
self.on_read_handle(data)
async def write(self, data: bytes):
if not self.ser:
return
# When the user types in the terminal, send it to the serial device
if not self._closed and self.ser.is_open:
# Ensure we encode to bytes
self.ser.write(data)
def close(self):
# Cleanup
if not self.ser:
return
self._closed = True
if self.ser.is_open:
self.ser.close()
def is_closed(self):
return self._closed
- Integrate your
SerialPortInterfacewithXTermin a NiceGUI app:
from nicegui import ui
from niceterminal.xterm import XTerm
# Instantiate our custom interface for a specific serial device
serial_interface = SerialPortInterface(port="COM4", baudrate=115200)
if __name__ == "__mp_main__":
serial_interface.start()
# Render in your NiceGUI app
ui.label("Serial Port Terminal")
# Create an XTerm bound to the serial interface
serial_terminal = XTerm(interface=serial_interface).classes("w-full h-full")
ui.run()
Now anything typed in the terminal is sent to the specified serial port, and anything received from the device is displayed in the terminal.
CLI Usage (niceterm)
Installing with [cli] provides the niceterm command, a convenient multi-terminal web interface:
NiceTerminal Web Interface
Usage:
niceterm [options]
niceterm -h | --help
niceterm --version
Options:
-h --help Show this help.
--version Show version.
--host=<host> Host to bind web interface [default: 0.0.0.0].
--port=<port> Port for web interface [default: 8080].
--app=<command> Default command to start in new terminals [default: bash].
--password=<pass> Set authentication password.
--no-auth Disable authentication requirement (cannot combine with --password).
--light-mode Use light mode theme.
--log-level=<level> Set log level [default: INFO].
--isolation=<level> At what level terminals are shared [default: global].
(global, user, or tab)
Examples
# Start with default settings on port 8080:
niceterm
# Start on port 9000, with no authentication:
niceterm --port 9000 --no-auth
# Provide a specific password:
niceterm --password secret123
# Run Python in each new terminal and isolate them per tab:
niceterm --app "python3" --isolation tab
On startup, logs display the server address and an auto-generated password (if --password wasn’t specified).
Screenshots
| Authentication Screen | Terminal Dashboard |
|---|---|
Simple auto-index page usage:
from nicegui import ui
from niceterminal.xterm import ShellXTerm
ShellXTerm().classes("w-full h-full")
ui.run()
Which yields:
Security Considerations
- Open Shell/Device Access: Running
nicetermor embedding a shell/serial interface in a publicly exposed NiceGUI app is risky. - Authentication: Always protect your deployment with strong passwords or other authentication methods if it’s internet-accessible.
- TLS/SSL: Consider using HTTPS or a secure reverse proxy for production. (or simply just... maybe not use this in production. This is an experimental library after all)
- Isolation Levels: With
niceterm, you can decide whether multiple users/tabs share the same terminal or have separate sessions.
License
This project is released under the MIT-0 License. You’re free to copy, modify, and distribute this software with no attribution required.
If you have suggestions, bug reports, or feature requests, please open an issue on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file niceterminal-0.1.3.tar.gz.
File metadata
- Download URL: niceterminal-0.1.3.tar.gz
- Upload date:
- Size: 99.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.22.2 CPython/3.10.12 Linux/5.15.0-97-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09b545a573831659c0a09dd62519933985ad11acd39f396241f6bede3d7dff37
|
|
| MD5 |
bd4d9fd8621417cf832d8f3b3bd32be5
|
|
| BLAKE2b-256 |
ad55fdbf7a1f4a98512e96dfe87f387e86e6d90e3725bdc762b9f1738c73beb6
|
File details
Details for the file niceterminal-0.1.3-py3-none-any.whl.
File metadata
- Download URL: niceterminal-0.1.3-py3-none-any.whl
- Upload date:
- Size: 101.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.22.2 CPython/3.10.12 Linux/5.15.0-97-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d70a9b66df2427feddbab18db8e818085e241c7628abd15cbb3223847cee22a8
|
|
| MD5 |
70f6ebba33a3f0b17a8812fc78b60880
|
|
| BLAKE2b-256 |
9fed94f80e0e1f6e221ecc3c603624a82c3d655bb5301ac12e3f43eeb74b645f
|