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.1.0.tar.gz (12.2 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.1.0-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

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

Hashes for uber_shell-1.1.0.tar.gz
Algorithm Hash digest
SHA256 1b9bf26028a325f32bdf37c0f7d40c81abd27aa3de9e871fcb726e425c02a619
MD5 43c04b2aae3a9d23a11ff970c7751fc0
BLAKE2b-256 89df94938b73ac6ae8f64bde749e24f04aeb9e73686fec38d109d3114ce8b97a

See more details on using hashes here.

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

Hashes for uber_shell-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 393ebeb2aceb6f52826da4cd2b59b4d82ff5edab03de3f13486582e59ef8c34a
MD5 3025d8c2240baebca5b26f68c57ab631
BLAKE2b-256 798169d73f3ae2e8793cd239bfce159320b032e725e42ccbdf15854e3960f865

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