# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/fastcore_patch_script.ipynb (unless otherwise specified).

__all__ = ['store_attr', 'clean_type_str', 'store_false', 'store_true', 'Param', 'CustomFormatter', 'anno_parser']

# Cell
try: from fastcore.all import *
except: pass
import argparse
import inspect

# Cell
def _store_attr(self, anno, **attrs):
    stored = self.__stored_args__
    for n,v in attrs.items():
        if n in anno: v = anno[n](v)
        setattr(self, n, v)
        stored[n] = v

def store_attr(names=None, self=None, but='', cast=False, **attrs):
    "Store params named in comma-separated `names` from calling context into attrs in `self`"
    fr = sys._getframe(1)
    args = fr.f_code.co_varnames[:fr.f_code.co_argcount]
    if self: args = ('self', *args)
    else: self = fr.f_locals[args[0]]
    if not hasattr(self, '__stored_args__'): self.__stored_args__ = {}
    anno = annotations(self) if cast else {}
    if not attrs:
        ns = re.split(', *', names) if names else args[1:]
        attrs = {n:fr.f_locals[n] for n in ns}
    if isinstance(but,str): but = re.split(', *', but)
    attrs = {k:v for k,v in attrs.items() if k not in but}
    return _store_attr(self, anno, **attrs)

# Cell
def clean_type_str(x:str):
    x = str(x)
    x = re.sub("(class|function|__main__\.|\ at.*)", '', x)
    x = re.sub("(<|>|'|\ )", '', x) # spl characters
    return x

#export
def store_false():
    "Placeholder to pass to `Param` for `store_false` action"
    pass

#export
def store_true():
    "Placeholder to pass to `Param` for `store_true` action"
    pass

# Cell
class Param:
    "A parameter in a function used in `anno_parser` or `call_parse`"
    def __init__(self, help=None, type=None, opt=True, action=None, nargs=None, const=None,
                 choices=None, required=None, metavar='', alias=None, default=None):
        if type==store_true:  type,action,default=None,'store_true' ,False
        if type==store_false: type,action,default=None,'store_false',True
        store_attr()

    def set_default(self, d):
        if self.default is None:
            if d==inspect.Parameter.empty:
                #self.opt = False
                self.default=None
            else: self.default = d
        if self.default is not None: self.help += f""

    @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' and k[0]!='_' and k!='alias'}
    def __repr__(self):
        if self.help is None and self.type is None: return ""
        if self.help is None and self.type is not None: return f"{clean_type_str(self.type)}"
        if self.help is not None and self.type is None: return f"<'{self.help}'>"
        if self.help is not None and self.type is not None: return f"{clean_type_str(self.type)} <'{self.help}'>"

# Cell
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,
                      argparse.RawDescriptionHelpFormatter,
                      #argparse.MetavarTypeHelpFormatter
                     ): pass

def anno_parser(func, prog=None, from_name=False):
    "Look at params (annotated with `Param`) in func and return an `ArgumentParser`"
    p = argparse.ArgumentParser(description=func.__doc__, prog=prog, formatter_class=CustomFormatter)
    for k,v in inspect.signature(func).parameters.items():
        param = func.__annotations__.get(k, Param())
        param.set_default(v.default)
        #p.add_argument(f"{param.pre}{k}", **param.kwargs)
        if param.opt is True:
            if param.alias is None: p.add_argument( f"--{k}", **param.kwargs)
            else: p.add_argument(f"-{param.alias}", f"--{k}", **param.kwargs)
    p.add_argument(f"--pdb", help="Run in pdb debugger", action='store_true')
    p.add_argument(f"--xtra", help="Parse for additional args", type=str)
    return p