Coverage for obj2cli/parser.py : 92%

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
1import inspect
2from logging import getLogger
4log = getLogger(__name__)
7class Parser:
8 def __init__(self, deftype=str):
9 self.deftype = deftype
11 def onearg(self, name, param, p):
12 log.debug("onearg param: %s", param)
13 if param.default != inspect._empty and param.default is not None:
14 dflt = param.default
15 else:
16 dflt = None
17 thint = param.annotation
18 if thint == inspect._empty:
19 if dflt is not None:
20 typ = type(dflt)
21 else:
22 log.debug("default type %s", self.deftype)
23 typ = self.deftype
24 else:
25 typ = thint
26 return {
27 "name": name,
28 "default": dflt,
29 "type": typ,
30 "kind": param.kind,
31 }
33 def inspect_flags(self, v):
34 res = []
35 for f in filter(lambda f: f.startswith("is") and callable(getattr(inspect, f)), dir(inspect)):
36 if getattr(inspect, f)(v):
37 res.append(f[2:])
38 return res
40 def parse_fn(self, fn):
41 sig = inspect.signature(fn)
42 log.debug("signature %s", sig)
43 res = {"flags": self.inspect_flags(fn), "args": [], "fn": fn, }
44 fndoc = inspect.getdoc(fn)
45 if fndoc is not None:
46 res['doc'] = fndoc
47 for name, param in sig.parameters.items():
48 res["args"].append(self.onearg(name, param, res))
49 if sig.return_annotation != inspect._empty:
50 res["return"] = sig.return_annotation
51 return res
53 def fn_args(self, data):
54 if "staticmethod" in data.get("flags", []):
55 args = data.get("args", [])
56 elif "classmethod" in data.get("flags", []):
57 args = data.get("args", [])
58 else:
59 args = data.get("args", [])[1:]
60 return args
62 def parse_new(self, cls):
63 return self.parse_fn(cls.__init__)
65 def parse_cls(self, cls):
66 if not inspect.isclass(cls):
67 cls = cls.__class__
68 res = {'__init__': self.parse_new(cls),
69 '__classmeta__': {
70 "class": cls,
71 "name": cls.__name__,
72 "qualname": cls.__qualname__,
73 "flags": self.inspect_flags(cls),
74 }}
75 clsdoc = inspect.getdoc(cls)
76 if clsdoc is not None:
77 res['doc'] = clsdoc
78 for m, fn in inspect.getmembers(cls, lambda f: callable(f)):
79 if m.startswith("_"):
80 continue
81 try:
82 res[m] = self.parse_fn(fn)
83 except ValueError as e:
84 log.error("cannot inspect %s: %s", m, e)
85 if "class" in res.get("__classmeta__"):
86 # class
87 kls = cls
88 else:
89 # object
90 kls = cls.__class__
91 for k, v in kls.__dict__.items():
92 if k not in res:
93 continue
94 if isinstance(v, staticmethod):
95 res[k]["flags"].append('staticmethod')
96 elif isinstance(v, classmethod):
97 res[k]["flags"].append('classmethod')
98 elif isinstance(v, property):
99 res[k]["flags"].append("property")
100 return res