Skip to main content

$ cli load from.yaml

Project description

GitHub Workflow Status (with branch) PyPI GitHub

cliffy :mountain:

cliffy is a YAML-defined CLI generator, manager, and builder for Python. It offers features to rapidly build, test, and deploy CLIs.

Features

  • Write CLIs with YAML manifests
  • Manage CLIs- load, test, update, list, and remove
  • Built-in shell and Python scripting support
  • Supports Jinja2 templating
  • Hot-reload CLIs on manifest changes for easier development
  • Build CLIs into self-contained, single-file portable zipapps for sharing

Load

  1. Define a manifest
# hello.yaml
name: hello
version: 0.1.0

commands:
  bash: $echo "hello from bash"
  python: print("hello from python")
  1. Load CLI
$ cli load hello.yaml

Parses hello.yaml to generate a Typer CLI and load it into the running Python environment.

  1. Run CLI directly

hello -h

hello-demo

For more examples, check examples directory.

Build

  1. Define a manifest
# requires.yaml
name: requires
version: 0.1.0

requires:
  - requests >= 2.30.0
  - six

imports:
  - import six

commands:
  bash: $echo "hello from bash"
  python: print("hello from python")
  py: |
    if six.PY2:
        print("python 2")
    if six.PY3:
        print("python 3")
  1. Build CLI
$ cli build requires.yaml -o dist

Builds a portable zipapp containing the CLI and its package requirements.

  1. Run CLI
./dist/requires -h

Usage

cli <command>

  • init <cli name> --raw: Generate a template CLI manifest for a new CLI
  • load <manifest>: Add a new CLI based on the manifest
  • render <manifest>: View generated CLI script for a manifest
  • list or ls: Output a list of loaded CLIs
  • update <cli name>: Reload a loaded CLI
  • remove <cli name> or rm <cli name>: Remove a loaded CLI
  • run <manifest> -- <args>: Runs a CLI manifest as a one-time operation
  • build <cli name or manifest>: Build a CLI manifest or a loaded CLI into a self-contained zipapp
  • info <cli name>: Display CLI metadata
  • dev <manifest>: Start hot-reloader for a manifest for active development

How it works

  1. Define CLI manifests in YAML files
  2. Run cli commands to load, build, and manage CLIs
  3. When loaded, cliffy parses the manifest and generates a Typer CLI that is deployed directly as a script
  4. Any code starting with $ will translate to subprocess calls via PyBash
  5. Run loaded CLIs straight from the terminal
  6. When ready to share, run build to generate portable zipapps built with Shiv

Install

  • pip install "cliffy[rich]" to include rich-click for colorful CLI help output formatted with rich.

or

  • pip install cliffy

Manifest template

Generated by cli init. For a barebones template, run cli init --raw

# cliffy v1 template
manifestVersion: v1

# The name of the CLI
# This will be used as the script name when invoking the CLI from the command line.
name: cliffy 

# The version of the CLI
# This should follow the standard semantic versioning format (e.g., 'MAJOR.MINOR.PATCH').
version: 0.1.0

# List of external CLI manifest paths to include into the main manifest
# Performs a deep merge of manifests sequentially in the order given to assemble a merged manifest
# and finally, deep merges the merged manifest with the main manifest.
includes: []

# List of Python dependencies required for the CLI
# Validated on CLI load and update
# Supports basic requirements specifier syntax.
requires: []

# A mapping defining manifest variables that can be referenced in any other blocks
# Environments variables can be used in this section with ${some_env_var} for dynamic parsing
# Supports jinja2 formatted expressions as values
# Interpolate defined vars in other blocks jinja2-styled {{ var_name }}.
vars:
    default_mood: happy

# A string block or list of strings containing any module imports
# These can be used to import any python modules that the CLI depends on.
imports:
    - import os
    - |
        from collections import defaultdict
        import re

# A list containing any helper functions
# Each element of the list can be a separate function
# These functions should be defined as strings that can be executed by the Python interpreter.
functions:
    - |
        def greet_name(name: str):
            print("hello " + name)

# A mapping containing any shared type definitions
# These types can be referenced by name in the args section to provide type annotations for params and options defined in the args section.
types:
    Language: str = typer.Option("english", "-l", help="Language to greet in", prompt=True)

# A mapping containing the arguments and options for each command
# Each key in the mapping should correspond to a command in the commands section
# The value should be a list of mappings representing the params and options for that command.
args:
    world: [--name|-n: str!]                      # a REQUIRED option
    greet.all: 
        - names: str!                             # a REQUIRED param as denoted by the ! at the end
        - mood: str = "{{default_mood}}"          # an OPTIONAL param that uses a manifest var as default
        - --language: Language                    # an option with a default that uses Language type as arg definition

# A mapping containing the command definitions for the CLI
# Each command should have a unique key- which can be either a group command or nested subcommands
# Nested subcommands are joined by '.' in between each level
# A special (*) wildcard can be used to spread the subcommand to all group-level commands
# The value is the python code to run when the command is called OR a list of bash commands to run (prefixed with $).
commands:
    # this is a parent command that will get invoked with: hello world
    world: 
        - |
            """
            Help text for list
            """
            greet_name("world")
        - $ echo "i can also mix-and-match this command script to run bash commands"
    
    # this is a nested command that will get invoked with: hello greet all
    greet.all: 
        - help: Help text for list.all       # you can also define help text like this
        - $ echo "hello all"                 # this is a bash command that will get converted to python subprocess call
        - print("greetings from python")     # this python code will get directly invoked

Development

poetry shell
cli -h

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

cliffy-0.3.8.tar.gz (22.6 kB view details)

Uploaded Source

Built Distribution

cliffy-0.3.8-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file cliffy-0.3.8.tar.gz.

File metadata

  • Download URL: cliffy-0.3.8.tar.gz
  • Upload date:
  • Size: 22.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.19

File hashes

Hashes for cliffy-0.3.8.tar.gz
Algorithm Hash digest
SHA256 db88a787d5be4ef553d8410f333e1e08ff391079349a9fd931cf1bb14cfd2adc
MD5 4eee9f17a47ac3a4fdbaf24af6f54dd0
BLAKE2b-256 0e369b2fca59409159ac49ac501c59743d39a136706b3e503106c0f7afa2a596

See more details on using hashes here.

File details

Details for the file cliffy-0.3.8-py3-none-any.whl.

File metadata

  • Download URL: cliffy-0.3.8-py3-none-any.whl
  • Upload date:
  • Size: 25.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.19

File hashes

Hashes for cliffy-0.3.8-py3-none-any.whl
Algorithm Hash digest
SHA256 3fe706e85440e9400f2fcdf782a69ae164f58e914c87e7b560eb30127cd3f57a
MD5 144fa584792b92a873a928a32f51254d
BLAKE2b-256 2ad959a21119289948f9c7c6ee7ffffe308de7a6fda472ddd4d08e8ad2d95d9f

See more details on using hashes here.

Supported by

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