Name | cliffy JSON |
Version |
0.3.8
JSON |
| download |
home_page | https://github.com/jaykv/cliffy |
Summary | $ cli load from.yaml |
upload_time | 2024-08-26 04:35:49 |
maintainer | None |
docs_url | None |
author | Jay |
requires_python | <4.0,>=3.9 |
license | None |
keywords |
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
[![GitHub Workflow Status (with branch)](https://img.shields.io/github/actions/workflow/status/jaykv/cliffy/python-app.yaml?branch=main)](https://github.com/jaykv/cliffy/actions)
[![PyPI](https://img.shields.io/pypi/v/cliffy)](https://pypi.org/project/cliffy/)
![GitHub](https://img.shields.io/github/license/jaykv/cliffy)
# 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
```yaml
# hello.yaml
name: hello
version: 0.1.0
commands:
bash: $echo "hello from bash"
python: print("hello from python")
```
2. Load CLI
```
$ cli load hello.yaml
```
Parses `hello.yaml` to generate a Typer CLI and load it into the running Python environment.
3. Run CLI directly
`hello -h`
![hello-demo](docs/images/hello.png)
For more examples, check [examples](examples/) directory.
### Build
1. Define a manifest
```yaml
# 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")
```
2. Build CLI
```
$ cli build requires.yaml -o dist
```
Builds a portable zipapp containing the CLI and its package requirements.
3. 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](https://github.com/tiangolo/typer) CLI that is deployed directly as a script
4. Any code starting with `$` will translate to subprocess calls via [PyBash](https://github.com/cliffy-sh/pybash)
5. Run loaded CLIs straight from the terminal
6. When ready to share, run `build` to generate portable zipapps built with [Shiv](https://github.com/linkedin/shiv)
## Install
* `pip install "cliffy[rich]"` to include [rich-click](https://github.com/ewels/rich-click) for colorful CLI help output formatted with [rich](https://github.com/Textualize/rich).
or
* `pip install cliffy`
## Manifest template
Generated by `cli init`. For a barebones template, run `cli init --raw`
```yaml
# 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
```
Raw data
{
"_id": null,
"home_page": "https://github.com/jaykv/cliffy",
"name": "cliffy",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": null,
"author": "Jay",
"author_email": "jay.github0@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/0e/36/9b2fca59409159ac49ac501c59743d39a136706b3e503106c0f7afa2a596/cliffy-0.3.8.tar.gz",
"platform": null,
"description": "[![GitHub Workflow Status (with branch)](https://img.shields.io/github/actions/workflow/status/jaykv/cliffy/python-app.yaml?branch=main)](https://github.com/jaykv/cliffy/actions)\n[![PyPI](https://img.shields.io/pypi/v/cliffy)](https://pypi.org/project/cliffy/)\n![GitHub](https://img.shields.io/github/license/jaykv/cliffy)\n\n# cliffy :mountain:\ncliffy is a YAML-defined CLI generator, manager, and builder for Python. It offers features to rapidly build, test, and deploy CLIs.\n\n## Features\n* Write CLIs with YAML manifests\n* Manage CLIs- load, test, update, list, and remove\n* Built-in shell and Python scripting support\n* Supports Jinja2 templating\n* Hot-reload CLIs on manifest changes for easier development\n* Build CLIs into self-contained, single-file portable zipapps for sharing\n\n### Load\n\n1. Define a manifest\n```yaml\n# hello.yaml\nname: hello\nversion: 0.1.0\n\ncommands:\n bash: $echo \"hello from bash\"\n python: print(\"hello from python\")\n```\n\n2. Load CLI\n```\n$ cli load hello.yaml\n```\nParses `hello.yaml` to generate a Typer CLI and load it into the running Python environment.\n\n3. Run CLI directly\n\n`hello -h`\n\n![hello-demo](docs/images/hello.png)\n\nFor more examples, check [examples](examples/) directory.\n\n### Build\n\n1. Define a manifest\n```yaml\n# requires.yaml\nname: requires\nversion: 0.1.0\n\nrequires:\n - requests >= 2.30.0\n - six\n\nimports:\n - import six\n\ncommands:\n bash: $echo \"hello from bash\"\n python: print(\"hello from python\")\n py: |\n if six.PY2:\n print(\"python 2\")\n if six.PY3:\n print(\"python 3\")\n```\n\n2. Build CLI\n```\n$ cli build requires.yaml -o dist\n```\n\nBuilds a portable zipapp containing the CLI and its package requirements.\n\n3. Run CLI\n```\n./dist/requires -h\n```\n\n## Usage\n`cli <command>`\n* `init <cli name> --raw`: Generate a template CLI manifest for a new CLI\n* `load <manifest>`: Add a new CLI based on the manifest\n* `render <manifest>`: View generated CLI script for a manifest\n* `list` or `ls`: Output a list of loaded CLIs \n* `update <cli name>`: Reload a loaded CLI\n* `remove <cli name>` or `rm <cli name>`: Remove a loaded CLI\n* `run <manifest> -- <args>`: Runs a CLI manifest as a one-time operation\n* `build <cli name or manifest>`: Build a CLI manifest or a loaded CLI into a self-contained zipapp\n* `info <cli name>`: Display CLI metadata\n* `dev <manifest>`: Start hot-reloader for a manifest for active development\n\n## How it works\n1. Define CLI manifests in YAML files\n2. Run `cli` commands to load, build, and manage CLIs\n3. When loaded, cliffy parses the manifest and generates a [Typer](https://github.com/tiangolo/typer) CLI that is deployed directly as a script\n4. Any code starting with `$` will translate to subprocess calls via [PyBash](https://github.com/cliffy-sh/pybash)\n5. Run loaded CLIs straight from the terminal\n6. When ready to share, run `build` to generate portable zipapps built with [Shiv](https://github.com/linkedin/shiv)\n\n## Install\n* `pip install \"cliffy[rich]\"` to include [rich-click](https://github.com/ewels/rich-click) for colorful CLI help output formatted with [rich](https://github.com/Textualize/rich).\n\nor \n\n* `pip install cliffy`\n\n## Manifest template\nGenerated by `cli init`. For a barebones template, run `cli init --raw`\n```yaml\n# cliffy v1 template\nmanifestVersion: v1\n\n# The name of the CLI\n# This will be used as the script name when invoking the CLI from the command line.\nname: cliffy \n\n# The version of the CLI\n# This should follow the standard semantic versioning format (e.g., 'MAJOR.MINOR.PATCH').\nversion: 0.1.0\n\n# List of external CLI manifest paths to include into the main manifest\n# Performs a deep merge of manifests sequentially in the order given to assemble a merged manifest\n# and finally, deep merges the merged manifest with the main manifest.\nincludes: []\n\n# List of Python dependencies required for the CLI\n# Validated on CLI load and update\n# Supports basic requirements specifier syntax.\nrequires: []\n\n# A mapping defining manifest variables that can be referenced in any other blocks\n# Environments variables can be used in this section with ${some_env_var} for dynamic parsing\n# Supports jinja2 formatted expressions as values\n# Interpolate defined vars in other blocks jinja2-styled {{ var_name }}.\nvars:\n default_mood: happy\n\n# A string block or list of strings containing any module imports\n# These can be used to import any python modules that the CLI depends on.\nimports:\n - import os\n - |\n from collections import defaultdict\n import re\n\n# A list containing any helper functions\n# Each element of the list can be a separate function\n# These functions should be defined as strings that can be executed by the Python interpreter.\nfunctions:\n - |\n def greet_name(name: str):\n print(\"hello \" + name)\n\n# A mapping containing any shared type definitions\n# These types can be referenced by name in the args section to provide type annotations for params and options defined in the args section.\ntypes:\n Language: str = typer.Option(\"english\", \"-l\", help=\"Language to greet in\", prompt=True)\n\n# A mapping containing the arguments and options for each command\n# Each key in the mapping should correspond to a command in the commands section\n# The value should be a list of mappings representing the params and options for that command.\nargs:\n world: [--name|-n: str!] # a REQUIRED option\n greet.all: \n - names: str! # a REQUIRED param as denoted by the ! at the end\n - mood: str = \"{{default_mood}}\" # an OPTIONAL param that uses a manifest var as default\n - --language: Language # an option with a default that uses Language type as arg definition\n\n# A mapping containing the command definitions for the CLI\n# Each command should have a unique key- which can be either a group command or nested subcommands\n# Nested subcommands are joined by '.' in between each level\n# A special (*) wildcard can be used to spread the subcommand to all group-level commands\n# The value is the python code to run when the command is called OR a list of bash commands to run (prefixed with $).\ncommands:\n # this is a parent command that will get invoked with: hello world\n world: \n - |\n \"\"\"\n Help text for list\n \"\"\"\n greet_name(\"world\")\n - $ echo \"i can also mix-and-match this command script to run bash commands\"\n \n # this is a nested command that will get invoked with: hello greet all\n greet.all: \n - help: Help text for list.all # you can also define help text like this\n - $ echo \"hello all\" # this is a bash command that will get converted to python subprocess call\n - print(\"greetings from python\") # this python code will get directly invoked\n\n```\n\n## Development\n```\npoetry shell\ncli -h\n```\n\n",
"bugtrack_url": null,
"license": null,
"summary": "$ cli load from.yaml",
"version": "0.3.8",
"project_urls": {
"Homepage": "https://github.com/jaykv/cliffy",
"Repository": "https://github.com/jaykv/cliffy"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "2ad959a21119289948f9c7c6ee7ffffe308de7a6fda472ddd4d08e8ad2d95d9f",
"md5": "144fa584792b92a873a928a32f51254d",
"sha256": "3fe706e85440e9400f2fcdf782a69ae164f58e914c87e7b560eb30127cd3f57a"
},
"downloads": -1,
"filename": "cliffy-0.3.8-py3-none-any.whl",
"has_sig": false,
"md5_digest": "144fa584792b92a873a928a32f51254d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 25624,
"upload_time": "2024-08-26T04:35:47",
"upload_time_iso_8601": "2024-08-26T04:35:47.928927Z",
"url": "https://files.pythonhosted.org/packages/2a/d9/59a21119289948f9c7c6ee7ffffe308de7a6fda472ddd4d08e8ad2d95d9f/cliffy-0.3.8-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0e369b2fca59409159ac49ac501c59743d39a136706b3e503106c0f7afa2a596",
"md5": "4eee9f17a47ac3a4fdbaf24af6f54dd0",
"sha256": "db88a787d5be4ef553d8410f333e1e08ff391079349a9fd931cf1bb14cfd2adc"
},
"downloads": -1,
"filename": "cliffy-0.3.8.tar.gz",
"has_sig": false,
"md5_digest": "4eee9f17a47ac3a4fdbaf24af6f54dd0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 22627,
"upload_time": "2024-08-26T04:35:49",
"upload_time_iso_8601": "2024-08-26T04:35:49.502256Z",
"url": "https://files.pythonhosted.org/packages/0e/36/9b2fca59409159ac49ac501c59743d39a136706b3e503106c0f7afa2a596/cliffy-0.3.8.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-26 04:35:49",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "jaykv",
"github_project": "cliffy",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "cliffy"
}