Hide keyboard shortcuts

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 

3 

4log = getLogger(__name__) 

5 

6 

7class Parser: 

8 def __init__(self, deftype=str): 

9 self.deftype = deftype 

10 

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 } 

32 

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 

39 

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 

52 

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 

61 

62 def parse_new(self, cls): 

63 return self.parse_fn(cls.__init__) 

64 

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