A Host/Plugin framework for building powerful interactive REPLs in Python.
Project description
Uber Shell
uber (prefix) Forming nouns denoting an outstanding, supreme, or pre-eminent example of its kind, or a person or thing markedly surpassing others of its class or type, as uber-fan, uber-model, [uber-shell] etc. Frequently in fashion and popular culture contexts.
A Host/Plugin framework for building powerful interactive REPLs (Read-Eval-Print Loops) in Python.
Uber Shell allows you to:
- Wrap an existing
clickCLI into an interactive shell with history and auto-completion. - Combine multiple independent CLIs into a single "Meta CLI" using Python Entry Points.
- Auto-discovery of compatible CLIs using entry-points.
- Add access to shell commands and other built-in utilities. User extensible.
- Help automatically builds summary of available commands.
It solves the "slow startup" problem by loading libraries once and running commands repeatedly in memory.
Installation
pip install uber-shell
Use Case 1: The "Single App" Mode
Add an interactive loop to your existing CLI tool (e.g., my-app).
1. In your CLI code
Import UberShell and register your Click group.
# my_app/cli.py
import click
from uber_shell import UberShell
@click.group()
def cli():
pass
@cli.command()
def hello():
click.echo("Hello World!")
@cli.command()
@click.option("--debug", is_flag=True)
def uber(debug):
"""Starts the interactive shell."""
shell = UberShell("my-app", debug)
# Register all commands in 'cli', except 'uber' (to avoid recursion)
shell.register_click_group(cli, exclude=["uber"])
shell.start()
if __name__ == "__main__":
cli()
2. Usage
$ my-app uber
my-app > hello
Hello World!
my-app >
Use Case 2: The "Host/Plugin" Mode (The "Uber Uber" Shell)
Create a "Host" application that automatically discovers and runs commands from other installed packages ("Plugins", e.g. quarto-tools, risk-engine).
Step 1: The Plugin (quarto-tools)
In the plugin's pyproject.toml, advertise the CLI entry point.
[project]
name = "quarto_tools"
# ...
# 1. Standard script (creates 'qt' executable)
[project.scripts]
qt = "quarto_tools.cli:entry"
# 2. Plugin Registration (Advertising to Uber Shell)
# The group name "great2.plugins" is an arbitrary contract you define.
[project.entry-points."uber.plugins"]
qt = "quarto_tools.cli:entry"
Don't forget to pip install -e . to register the entry point!
Step 2: The Host
Uber provides a default host application, use load_plugins to find everyone registered under your group name. This code can be duplicated in your own project.
# uber_tools/cli.py
import click
from . import UberShell
@click.group()
def cli():
pass
@cli.command()
@click.option("--debug", is_flag=True)
def uber(debug):
"""The uber/uber (Master) Shell."""
shell = UberShell("great2", debug)
# 1. Register Host commands
shell.register_click_group(cli, exclude=["uber"])
# 2. Auto-discover Plugins
# This scans site-packages for anyone registered to "great2.plugins"
shell.load_plugins("great2.plugins")
shell.start()
Step 3: The Experience
The load_plugins method provides Nested Access. If the plugin has an uber command, typing the plugin name (e.g., qt) enters that plugin's specific sub-loop.
$ uber
uber >
uber > archivum
uber > archivum >
uber > archivum > toc # Runs archivum directly
uber > archivum > .. # Move up to the parent (also x, q, quit, exit)
uber >
uber > qt toc # Enter the QT sub-shell and run toc command...
uber > qt > x # Exit back to host
great2 >
Advanced Features
Python Shortcuts
You can register raw Python functions to the shell, bypassing Click entirely.
from my_lib import heavy_calculation
shell.register_command("calc", lambda line: heavy_calculation())
Startup Scripts
You can pass a list of commands to run immediately on startup.
@cli.command()
@click.argument("script", required=False)
def uber(script):
initial_cmds = [script] if script else None
shell.start(startup_commands=initial_cmds)
System Fallback
If a command is not found in the registry, UberShell falls back to the system shell. This means you can run dir, git status, or ripgrep directly from the prompt.
great2 > rg "class UberShell"
Built-ins
cd [path]: Change working directory (smart path completion included).cls: Clear screen (Windows).ev: Launch "Everything" search (Windows).pwd: Print working directory.q/x/exit: Quit.
File Structure
uber-shell/
├── pyproject.toml # Dependencies: click, prompt_toolkit
├── README.md # The documentation below
├── src/
│ └── uber_shell/
│ ├── __init__.py # Exposes UberShell and factories
│ └── shell.py # The core logic
├── docs/ # Documentation (maybe)
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 uber_shell-1.1.0.tar.gz.
File metadata
- Download URL: uber_shell-1.1.0.tar.gz
- Upload date:
- Size: 12.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b9bf26028a325f32bdf37c0f7d40c81abd27aa3de9e871fcb726e425c02a619
|
|
| MD5 |
43c04b2aae3a9d23a11ff970c7751fc0
|
|
| BLAKE2b-256 |
89df94938b73ac6ae8f64bde749e24f04aeb9e73686fec38d109d3114ce8b97a
|
File details
Details for the file uber_shell-1.1.0-py3-none-any.whl.
File metadata
- Download URL: uber_shell-1.1.0-py3-none-any.whl
- Upload date:
- Size: 10.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
393ebeb2aceb6f52826da4cd2b59b4d82ff5edab03de3f13486582e59ef8c34a
|
|
| MD5 |
3025d8c2240baebca5b26f68c57ab631
|
|
| BLAKE2b-256 |
798169d73f3ae2e8793cd239bfce159320b032e725e42ccbdf15854e3960f865
|