sayed99's picture
project upload
cc9dfd7
import os, sys, subprocess, inspect
from dataclasses import dataclass
from typing import Any
from argparse import ArgumentParser
@dataclass
class Param():
"A parameter in a function used in `anno_parser` or `call_parse`"
help:str=None
type:type=None
opt:bool=True
action:str=None
nargs:str=None
const:str=None
choices:str=None
required:bool=None
@property
def pre(self): return '--' if self.opt else ''
@property
def kwargs(self): return {k:v for k,v in self.__dict__.items()
if v is not None and k!='opt'}
def anno_parser(func):
"Look at params (annotated with `Param`) in func and return an `ArgumentParser`"
p = ArgumentParser(description=func.__doc__)
for k,v in inspect.signature(func).parameters.items():
param = func.__annotations__.get(k, Param())
kwargs = param.kwargs
if v.default != inspect.Parameter.empty: kwargs['default'] = v.default
p.add_argument(f"{param.pre}{k}", **kwargs)
return p
def call_parse(func):
"Decorator to create a simple CLI from `func` using `anno_parser`"
name = inspect.currentframe().f_back.f_globals['__name__']
if name == "__main__":
args = anno_parser(func).parse_args()
func(**args.__dict__)
else: return func
def call_plac(f):
"Decorator to create a simple CLI from `func` using `plac`"
name = inspect.currentframe().f_back.f_globals['__name__']
if name == '__main__':
import plac
res = plac.call(f)
if callable(res): res()
else: return f