Coverage for obj2cli/argparse.py : 68%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from inspect import Parameter
2from logging import getLogger
3import datetime
4import enum
5import argparse
6import argparse_utils
7from .parser import Parser
9log = getLogger(__name__)
12class Argparse:
13 parser = Parser()
15 def __init__(self, positional: bool = False):
16 self.positional = positional
18 def onearg(self, arg, p):
19 optname = arg.get("name")
20 if len(optname) == 1:
21 optname = "-" + optname
22 else:
23 optname = "--" + optname
24 kwargs = {
25 'type': arg.get("type", str),
26 'default': arg.get("default"),
27 'help': arg.get("doc"),
28 'metavar': arg.get('type', str).__name__,
29 }
30 # custom action
31 if kwargs.get('type') == datetime.datetime:
32 kwargs['action'] = argparse_utils.datetime_action()
33 kwargs.pop('type')
34 elif kwargs.get('type') == datetime.date:
35 kwargs['action'] = argparse_utils.date_action()
36 kwargs.pop('type')
37 elif kwargs.get('type') == datetime.time:
38 kwargs['action'] = argparse_utils.time_action()
39 kwargs.pop('type')
40 elif kwargs.get('type') == datetime.timedelta:
41 kwargs['action'] = argparse_utils.timedelta_action()
42 kwargs.pop('type')
43 elif issubclass(kwargs.get('type'), enum.Enum):
44 kwargs['action'] = argparse_utils.enum_action(kwargs.get('type'))
45 kwargs['help'] = "/".join(kwargs.get('type').__members__.keys())
46 kwargs.pop('type')
47 elif kwargs.get('type') == dict:
48 kwargs['action'] = argparse_utils.json_action()
49 kwargs.pop('type')
50 elif kwargs.get('type') == bool:
51 kwargs.pop('type')
52 kwargs.pop('metavar')
53 if kwargs.get('default', False):
54 kwargs['action'] = "store_false"
55 else:
56 kwargs['action'] = "store_true"
57 log.debug("kwargs %s", kwargs)
59 # by kind(positional/keyword)
60 if arg.get("kind") == Parameter.POSITIONAL_ONLY:
61 p.add_argument(arg.get("name"), **kwargs)
62 elif arg.get("kind") == Parameter.VAR_POSITIONAL:
63 p.add_argument(arg.get("name"), nargs='*', **kwargs)
64 elif arg.get("kind") == Parameter.VAR_KEYWORD:
65 pass
66 # p.add_argument(optname, **kwargs)
67 elif arg.get("kind") == Parameter.POSITIONAL_OR_KEYWORD:
68 if self.positional:
69 p.add_argument(arg.get("name"), nargs=1, **kwargs)
70 else:
71 p.add_argument(optname, **kwargs)
72 elif arg.get("kind") == Parameter.KEYWORD_ONLY:
73 p.add_argument(optname, **kwargs)
75 def convert_fn(self, name, data, p=None):
76 log.debug("convert_fn name=%s, data=%s", name, data)
77 if p is None:
78 p = argparse.ArgumentParser(prog=name, description=data.get("doc"))
79 else:
80 p.description = data.get("doc")
81 p.set_defaults(__FUNCNAME__=name, __FUNC__=data.get("fn"))
82 log.debug("fn %s, args=%s", name, [
83 x.get("name") for x in data.get("args", [])])
84 args = self.parser.fn_args(data)
85 log.debug("args=%s", [x.get("name") for x in args])
86 for i in args:
87 self.onearg(i, p)
88 return p
90 def convert_cls(self, data, p=None):
91 if p is None:
92 name = data.get("__classmeta__", {}).get("name")
93 p = argparse.ArgumentParser(prog=name, description=data.get("doc"))
94 else:
95 p.description = data.get("doc")
96 p.set_defaults(__CLASSMETA__=data.get("__classmeta__"))
97 self.convert_fn("new", data.get("__init__"), p)
98 subs = p.add_subparsers()
99 for k, v in data.items():
100 log.debug("do1 k=%s v=%s", k, v)
101 if k == "__classmeta__":
102 log.debug("classmeta %s", v)
103 continue
104 if k == "__init__":
105 log.debug("new %s", v)
106 continue
107 if k == "doc":
108 log.debug("doc %s", v)
109 continue
110 s = subs.add_parser(k, help=v.get("doc"))
111 self.convert_fn(k, v, s)
112 return p
114 def fn_arg(self, fdata, parsed):
115 kw = {}
116 pos = []
117 for ag in fdata.get("args", []):
118 name = ag.get("name")
119 if name is None:
120 log.debug("name is none")
121 continue
122 if not hasattr(parsed, name):
123 log.debug("has no %s", name)
124 continue
125 if ag.get("kind") in (Parameter.POSITIONAL_ONLY, Parameter.VAR_POSITIONAL):
126 pos.extend(getattr(parsed, name))
127 elif ag.get("kind") == Parameter.POSITIONAL_OR_KEYWORD and self.positional:
128 pos.extend(getattr(parsed, name))
129 else:
130 kw[name] = getattr(parsed, name)
131 return kw, pos
133 def split_arg(self, data, parsed):
134 carg_kw, carg_pos = self.fn_arg(data.get("__init__", {}), parsed)
135 farg_kw, farg_pos = self.fn_arg(
136 data.get(parsed.__FUNCNAME__, {}), parsed)
137 return ((carg_pos, carg_kw), (farg_pos, farg_kw))