File size: 1,590 Bytes
cc9dfd7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
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
|