Skip to main content

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:

  1. Wrap an existing click CLI into an interactive shell with history and auto-completion.
  2. Combine multiple independent CLIs into a single "Meta CLI" using Python Entry Points.
  3. Auto-discovery of compatible CLIs using entry-points.
  4. Add access to shell commands and other built-in utilities. User extensible.
  5. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uber_shell-1.0.0.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uber_shell-1.0.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file uber_shell-1.0.0.tar.gz.

File metadata

  • Download URL: uber_shell-1.0.0.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for uber_shell-1.0.0.tar.gz
Algorithm Hash digest
SHA256 4c9eebbd8a92cf4c64be26662e16ac03cfee495f610e219cd8cb79d4b9a60aad
MD5 d3791e4f21ad3545c3130c2e3169697c
BLAKE2b-256 94edc629c0ededc3ab8b8cb7116b4a33ab3e0a55ecdc4a34960a46e4b1712b67

See more details on using hashes here.

File details

Details for the file uber_shell-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: uber_shell-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for uber_shell-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 37b33943b05923ae8975e5fbffdcb131546b63db5e810f2027e5680283762ec0
MD5 67b3dff6dbfe778b688b6c4ec7800180
BLAKE2b-256 458ca529b8db32452d73572204c8a44913eea4c0b543b4fcb78b5880b73c48f0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page