Skip to content

Yapx

The easiest way to create Python CLI Apps.

Documentation | Git Repo

License GitHub tag (with filter) GitHub last commit (branch) GitHub Repo stars

Yapx is Yeah, Another Argparse eXtension, a Python library for creating CLI tools -- even textual user interfaces (TUIs) -- by analyzing type-hints of Python functions and dataclasses.

Yapx features include:

  • :white_check_mark: Native type-casting and validation of CLI arguments based on type-hints
  • :white_check_mark: Infinitely-nested commands and subcommands
  • :white_check_mark: Automatic addition of "helpful" arguments, including --help, --help-all, and --version.
  • :white_check_mark: Display your CLI as a TUI (with argparse-tui)
  • :white_check_mark: Handling of unknown arguments using *args and **kwargs
  • :white_check_mark: Define feature-flag parameters (like --dev / --test / --prod)
  • :white_check_mark: Define counting parameters (like -vvv)
  • :white_check_mark: No 3rd-party dependencies required (but can be opted into)
  • :white_check_mark: Type-casting and validation, with or without Pydantic.
  • :white_check_mark: Prettier help and error messages (with rich-argparse)
  • :white_check_mark: Command-line autocompletion scripts (with shtab)

Hello World Example

Once you install Yapx, you can save the following to a file named scratch.py...

#!/usr/bin/env python3

import yapx


def say_hello(name, times: int = 1, exclaim: bool = False):
    # Print this message
    msg = f"Hello {name}"

    if exclaim:
        msg += "!"

    for n in range(times):
        print(msg)


yapx.run(say_hello)

Make this file executable (chmod +x ./scratch.py), then a call to ./scratch.py --help will output the CLI help menu:

➜ ./scratch.py --help

________________________________________________________________________________

$ scratch.py
________________________________________________________________________________

Helpful Parameters:
  --help, -h            Show this help message.
  --help-all            Show help for all commands.
  --print-shell-completion {bash,zsh,tcsh}
                        Print shell completion script.
  --tui                 Show Textual User Interface (TUI).

Required Parameters:
  --name <value>

Optional Parameters:
  --times <#>           | Default: 1
  --exclaim

Usage: scratch.py [--help | --help-all | --print-shell-completion {bash,zsh,tcsh} | --tui]
                --name <value> [--times <#>] [--exclaim]

A call to ./scratch.py --tui will open:

And executing ./scratch.py --name World --times 3 --exclaim will output:

Hello World!
Hello World!
Hello World!

Install

The base install can be obtained from PyPi:

pip install yapx

You can opt into extra functionality with these extras:

Pydantic

Install Yapx with Pydantic:

pip install 'yapx[pydantic]'

Yapx can handle builtin types such as str, int, bool; even list, set, and dict.

If type-casting fails and Pydantic is available, Yapx will attempt to use it for casting / type-validation.

#!/usr/bin/env python3

import yapx

from pydantic.networks import IPvAnyAddress
# TODO: from pydantic_extra_types import Color
# TODO: from pydantic_extra_types import SemanticVersion
# TODO: from pydantic_extra_types import PhoneNumber
# TODO: constr, confloat, conint


# Pydantic is used to cast the argument `ip` to a `IPvAnyAddress`
def translate_ip(ip: IPvAnyAddress): ...


yapx.run(translate_ip)

Yaml

Install Yapx with a YAML parser (PyYaml) to gain the ability to build a parser from a Yaml file:

pip install 'yapx[yaml]'

With this installed, you could write the following definition to a YAML file named scratch.yml...

'hello-world-cli':
  arguments:
    name:
      type: str
    times:
      type: int
      default: 1
    exclaim:
      type: bool
      default: false
  # subparsers:
  #   'test-subcmd':
  #     arguments: {}
  #     subparsers: {}

...then you can use Yapx to construct a parser by pointing it to the YAML file:

#!/usr/bin/env python3

import yapx

parser = yapx.build_parser_from_file("scratch.yml")

parser.parse_args()

JSON works, too, without the need for a 3rd-party library.

Rich

Add colors and improve the readability of help output by installing rich and rich-argparse along with Yapx:

pip install 'yapx[rich]'

Shell Completion

When shtab is installed along with Yapx, CLIs inherit the flag --print-shell-completion {bash,zsh,tcsh} which will output shell completion script:

pip install 'yapx[shtab]'

Read more about shell completion here.

TUI

The TUI capability demonstrated in the "Hello World" example is powered by argparse-tui. Install it as a Yapx extra using:

pip install 'yapx[tui]'

Extras

Install Yapx with all of the extras:

pip install 'yapx[extras]'

Example Use

Yapx is a superset of Python's native Argparse ArgumentParser, so you can make use of the high-level abstractions or do the low-level work you're familiar with.

yapx.run

yapx.run is the easiest way to (1) build a parser, (2) parse CLI arguments, and (3) call the appropriate function.

Recall the "Hello World" example:

def say_hello(name, times: int = 1, exclaim: bool = False): ...


yapx.run(say_hello)

yapx.ArgumentParser

You can also use yapx.ArgumentParser as you would a native ArgumentParser:

import yapx

parser = yapx.ArgumentParser()

parser.add_argument("--name")
parser.add_argument("--times", type=int, default=1)
parser.add_argument("--exclaim", type=bool, action="store_true")

parser.print_help()

You can use the plural add_arguments method to add arguments from a dataclass:

import yapx
from dataclases import dataclass


@dataclass
class HelloWorldArgs:
    name: str
    times: int = 1
    exclaim: bool = False


parser = yapx.ArgumentParser()

parser.add_arguments(HelloWorldArgs)

parser.print_help()

The add_arguments method also accepts functions:

import yapx


def say_hello(name, times: int = 1, exclaim: bool = False): ...


parser.add_arguments(say_hello)

parser.print_help()

Annotations

When you annotate your function arguments or dataclass properties, you are defining argparse arguments.

TODO: test with yapx.arg(default=rich.Prompt('what is your name?')

Customizing Arguments

TODO:

  • help text
  • boolean flags
  • environment variables
  • positional args
  • counting parameters
  • feature-flag parameters

Advanced Use

TODO:

  • --help-export, --help-export-all file.[svg|html|txt]

  • subcommands

    • command chaining
  • yapx.Context

    • relay value
    • condition whether Context is None
  • repeating parameters (also address special case where root cmd and subcmd share a flag)

  • *args and **kwargs

  • constraining input values