Skip to content

Instantly share code, notes, and snippets.

@raven4752
Created June 13, 2021 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raven4752/c522a2e81d4046da5922c3b1e08f292f to your computer and use it in GitHub Desktop.
Save raven4752/c522a2e81d4046da5922c3b1e08f292f to your computer and use it in GitHub Desktop.
expose python function to cmd in one line
"""
a lazy wrapper to export python function directly as command line interface with one line of code
"""
import click
from functools import wraps, partial
import inspect
def get_prefix(key: str, prefix_set: set):
for i in range(1, len(key)):
if key[:i] not in prefix_set:
prefix_set.add(key[:i])
return key[:i]
def parse_doc_string(f):
"""
parse func string and return a map with param name as key and param doc as value and func description
"""
params_name_doc_map = {}
func_desc = ""
if f.__doc__:
for line in f.__doc__.split('\n'):
if not func_desc and line:
func_desc = line
if line.strip().startswith(":param"):
line = line.replace(":param", "").strip().split(":")
if len(line) == 2:
params_name_doc_map[line[0]] = line[1]
return params_name_doc_map, func_desc
def lazy_cmd(func, cli_group: click.group = None):
signature = inspect.signature(func)
prefix_set = set()
param_doc_map, func_desc = parse_doc_string(func)
f = func
if func_desc:
f.__doc__ = func_desc
for k, v in signature.parameters.items():
prefix = get_prefix(k, prefix_set)
help_k = param_doc_map.get(k, "")
if v.default is v.empty:
f = click.option('-' + prefix, '--' + k, help=help_k, required=True)(f)
else:
f = click.option('-' + prefix, '--' + k, help=help_k, default=v.default)(f)
if cli_group is not None:
f = cli_group.command()(f)
else:
f = click.command()(f)
@wraps(func)
def with_lazy_option_and_cmd(*args, **kwargs):
"""
use functions default params as click options
:param args:
:param kwargs:
:return:
"""
return f(*args, **kwargs)
return with_lazy_option_and_cmd
@click.group()
def cli():
pass
@partial(lazy_cmd, cli=cli)
def bar(foo):
print("bar " + foo)
@partial(lazy_cmd, cli=cli)
def foo(bar, count=1):
"""
func def
:param bar: sss
:param count: foo name
:return:
"""
for n in range(count):
print(bar)
if __name__ == '__main__':
cli()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment