Yapx
The easiest way to create Python CLI Apps.
Documentation | Git Repo
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