| | 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 |
| |
|
| |
|