Automatically generate a simple CLI.


Keywords
python
License
MIT
Install
pip install funcli==0.7.1

Documentation

FunCLI PyPI

Automatically generate a simple CLI.

Installation

pip install funcli

Basic Usage

def main(*args: int):
	"""
		Adds numbers together.
		
		:param args: some numbers
	"""
	print("Sum:", sum(args))

if __name__ == '__main__':
	import funcli
	funcli.main()

# $ python sum.py 1 2 3
# Sum: 6

--help is autogenerated by the backend (argparse):

$ python sum.py -h
usage: sum.py [-h] [args [args ...]]

Adds numbers together.

positional arguments:
	args        some numbers

optional arguments:
	-h, --help  show this help message and exit

Advanced Usage

from typing import Optional, List

def foo(): pass
def bleep(): pass
def bloop(a, b: int = 0, *c: str, d: Optional[List[float]] = None):
	print("Args:", a, b, c, d)

if __name__ == '__main__':
	import funcli
	funcli.main({ 'foo': foo, 'bar': { bleep, bloop } })

# $ python advanced.py bar bloop arg0 c0 c1 --b=987 --d 42 -0.3
# Args: arg0 987 ('c0', 'c1'), [42, -0.3]

Reference

funcli.main(spec = None)

Sugar. spec defaults to the main function from the caller's scope. Calls funcli.run on spec, and calls sys.exit with the return value.

funcli.run(spec, args = None, converters = None)
  • spec is either a callable, a sequence of callables, or a dict mapping strings to nested specs
  • args default to sys.argv[1:]
  • converters is a mapping from types (or whatever you want to use as annotations) to a function that parses a command line argument

Given functions foo, bar, baz, here are some sample invocations:

funcli.run(foo, ['arg0']) # Calls foo('arg0')
funcli.run({ foo, bar }, ['bar', 'arg0']) # Calls bar('arg0')
funcli.run({ 'beep': foo, 'bloop': [bar, baz] }, ['beep', 'arg0']) # Calls foo('arg0')
funcli.run({ 'beep': foo, 'bloop': [bar, baz] }, ['bloop', 'bar', 'arg0']) # Calls bar('arg0')

bool arguments

Non-optional bool values should be passed as True and False on the command line. Optional bool values, on the other hand, must be omitted.

def f(warnings: bool = False): ...
funcli.run(f, ['--warnings']) # f(warnings = True)

Note: currently, if the default value is True, there is no way to pass False.

Converters

Built-in converters handle int, float, bool, and pathlib.Path. Unannotated args are kept as a str. Basic sequence types (list/List[T], set/Set[T], tuple/Tuple[T, ...], Iterable[T], Sequence[T]) are supported, but only as optional arguments, e.g.:

def f(mylist: List[int] = []): ...
funcli.run(f, ['--mylist', '1', '2']) # f([1, 2])

Optional[T] is supported, but there's currently no way to explicitly pass None values.

Notes

Because of argparse limitations:

  • **kwargs aren't supported; if your function has them, they'll always be empty
  • optional arguments cannot be positional; f(a = 'default') has to be invoked as python foo.py --a=nondefault