Skip to main content

Easy CLIs from function inspection

Project description

CLI

An extremely easy to use library to generate python CLIs from functions through introspection.

Automatically generate the equivalent of this:

import argparse
parser = argparse.ArgumentParser(description="Generate a cryptographic token with a given entropy.")
parser.add_argument('method', nargs='?', default='xkcd', choices=('xkcd', 'short'))
parser.add_argument('entropy', nargs='?', default=70, type=int)
args = parser.parse_args()

if args.method == 'xkcd':
    print(xkcd(args.entropy))
else:
    print(alphanumeric(args.entropy))

from this:

from cli import Choice, cli

def token(method:Choice('xkcd', 'short')='xkcd', entropy=70):
    "Generate a cryptographic token with a given entropy."
    if method == 'xkcd':
	return xkcd(entropy)
    else:
	return alphanumeric(entropy)

cli(token)()

Explicitly, cli(token) creates a new function that accepts an array of strings, parses and automatically converts them according to rules derived from the function signature, applies the parsed arguments to the original token and prints the output. cli(token)() calls that function using the default sys.argv.

But wait, there's more!

Keyword arguments (optional or mandatory) are supported as is one varargs argument per function. Arguments will be automatically converted into the type of their default argument (if it is not None) or their type annotation.

The exact mapping from function signature to argparse rules is specified in the docstring of generate_parser(), but the idea is that it should be fairly intuitive.

You can even generate CLIs for a whole module (or any other object with function attributes):

import example
from cli import cli, opportunistic, coerce_number

# You can use opportunistic(coerce_number) to convert any string that looks
# like a number to a number so you don't have to annotate all the functions in a
# module. YMMV.
cli(example, default_type=opportunistic(coerce_number))()

# If you want one, you can get a reference to the current module with
# sys.modules[__name__]

Lower level API

generate_parser(your_function_here) will return an argparse.Parser instance. apply_namespace(your_function_here, namespace) will apply a namespace object (as returned by parser.parse_args()) to a function.

generate_parser_obj(your_module_or_class_here) will return an argparse.Parser with one subparser per callable on the

Code quality

The code is very short, clearly documented inline and all advertised features are tested.

Reference

Function signature interpretation: - (POSITIONAL_ONLY, POSITIONAL_OR_KEYWORD) = positional - positional with default = optional positional - KEYWORD_ONLY = options - defaults = defaults - Boolean special casing - If the default is True or False, the option does not take any arguments. Instead, if the option is given on the commandline, the opposite value to the default is given to the function. - Example: ```python def rm(*, force=False): pass

	cli(rm)(['--force']) # ~== rm(force=True)
	cli(rm)([]) # ~== rm(force=False)
	```
- type annotations = type
- If the `type` is callable, it is called by `argparse` on the relevant substring
- If the type is `bool`, it is replaced by `coerce_bool`
- Provide your own custom function or handle the strings in your
  function body if you need something fancier.

Special types: - cli.Choice - def foo(x:Choice(1,2)) interpreted as add_argument('x', choices=(1,2), type=int)

def example(positional, arguments):
    pass

def defaults(normally_one=1):
    pass

def typed(positional:bool, positional2:int):
    pass

# keyword some-positional-arg --keyword2=foo --keyword1=4
def keyword(positional, *, keyword1=3, keyword2='default_filename'):
    pass

# Mandatory keywords are bad, but you can have them if you want.
def mandatory_keywords(positional, *, keyword1, keyword2):
    pass

def varargs(pos1, pos2, *rest):
    pass

def choice_from_list(person:Choice('Ann', 'Bob', 'Charlie'))
    pass

# `flags --flag` is similar to flags(flag=True)
# `flags --inverse_flag` is similar to flags(inverse_flag=False)
def flags(*, flag=False, inverse_flag=True):
    pass

Related work

Other nice ways to make CLIs:

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

cmcaine-cli-0.0.2.tar.gz (5.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cmcaine_cli-0.0.2-py3-none-any.whl (7.0 kB view details)

Uploaded Python 3

File details

Details for the file cmcaine-cli-0.0.2.tar.gz.

File metadata

  • Download URL: cmcaine-cli-0.0.2.tar.gz
  • Upload date:
  • Size: 5.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.28.1 CPython/3.7.3

File hashes

Hashes for cmcaine-cli-0.0.2.tar.gz
Algorithm Hash digest
SHA256 c97fd417710fef899f0bdeca9db068e8e27a21ed394003d2e5223118b8acbda6
MD5 d6c29476425c57c4c7133e31bd4e30d1
BLAKE2b-256 db853fa8bf77d97cdc4bf69740dd0b5fe5caee8032b90e58dfffcbafed59ae92

See more details on using hashes here.

File details

Details for the file cmcaine_cli-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: cmcaine_cli-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 7.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.28.1 CPython/3.7.3

File hashes

Hashes for cmcaine_cli-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 03c327dc5810932f25d1cdcba89a3209103294e14913fb5c68e379b2e39ae375
MD5 a5c01f5deede59f841ae9c62b4f6f8e9
BLAKE2b-256 9b32cd8394cd97bcd2307821e764c35b9081ac0cfef35aeffa217bf4599c605b

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