#!/usr/bin/python3 #parses the output of /usr/sbin/kamctl rpc app_python.api_list # #usage ./kemi_mock.py api.json > KSR.py #or for python 3.2 #./kemi_mock.py api.json --no-union > KSR.py import json import sys from collections import defaultdict #python 3.2 doesnt support types.Union noUnion = False reserved_keywords = {"async"} def printMocReturn(module_name, func, indent): param_names = [] param_list = [] param_signature = "" if func['params'] is not None and func['params'] != 'none': param_list = func['params'].split(", ") i = 0 for _ in param_list: param_names.append("param"+str(i)) i = i + 1 param_signature = ", ".join(param_names) prefix = "" for i in range(indent): prefix = prefix+"\t" print(prefix + "if \""+func['name']+"\" not in _mock_data['"+module_name+"']:") printDefaultReturn(func, indent+1) print(prefix + "node = _mock_data['"+module_name+"']['"+func['name']+"']") print(prefix + "if isinstance(node, types.FunctionType):") print(prefix + "\treturn node("+param_signature+")") for param in param_names: print(prefix + "if not isinstance(node, dict):") print(prefix + "\treturn node") print(prefix + "if str(" + param + ") in node:") print(prefix + "\tnode = node[str("+param+")]") print(prefix + "else:") printDefaultReturn(func, indent+1) print(prefix + "return node") def printDefaultReturn(func, indent): prefix = "" for i in range(indent): prefix = prefix+"\t" if func['ret'] == "bool": print(prefix + "return True") elif func['ret'] == "int": print(prefix + "return 1") elif func['ret'] == "str": print(prefix + "return \"\"") elif func['ret'] == "xval": print(prefix + "return None") else: print(prefix + "return") def printFunction(module_name, func, indent): params = "" log_params = "" if module_name == "": log_params = "\"" + func['name'] + "\"" else: log_params = "\"" + module_name + "." + func['name'] + "\"" log_format_params = "%s" param_list = [] if func['params'] is not None and func['params'] != "none": param_list = func['params'].split(", ") i = 0 for _ in param_list: if params != "": params = params + ", " params = params + "param" + str(i) + ": " + param_list[i] log_params = log_params + ", param" + str(i) log_format_params = log_format_params + ", %s" i = i+1 if len(param_list) > 0: log_params = "(" + log_params + ")" prefix = "" for i in range(indent): prefix = prefix+"\t" if indent > 0: print(prefix + "@staticmethod") if func['ret'] == "bool": print(prefix + "def " + func['name'] +"("+params+") -> bool:") elif func['ret'] == "int": print(prefix + "def " + func['name'] +"("+params+") -> int:") elif func['ret'] == "str": print(prefix + "def " + func['name'] + "(" + params + ") -> int:") elif func['ret'] == "xval": if noUnion: print(prefix + "def " + func['name'] + "(" + params + "):") else: print(prefix + "def " + func['name'] +"("+params+") -> Union[int, str, None]:") else: print(prefix + "def " + func['name'] +"("+params+"):") generate_function_doc(module_name, func, prefix) print(prefix + "\tprint(\"Calling " + log_format_params + "\" % "+log_params+")") printMocReturn(module_name, func, indent+1) print("") def generate_function_doc(module_name, func, prefix): if documentation is not None and module_name in documentation: function_parts = func['name'].split("_") for i in range(len(function_parts), 0, -1): function_prefix = "_".join(function_parts[:i]) if function_prefix in documentation[module_name]["functions"]: print(prefix + "\t\"\"\"") documentation_lines = documentation[module_name]["functions"][function_prefix].split("\n") for line in documentation_lines: print(prefix + "\t" + line.replace("\\", "\\\\\\\\")) print(prefix + "\t\"\"\"") break classes = defaultdict(list) if len(sys.argv) < 2: print("Please specify the json file to parse") sys.exit(-1) documentation = None if len(sys.argv) > 2: for i in range(2,len(sys.argv)): if sys.argv[i] == "--no-union": noUnion = True else: with open(sys.argv[i]) as f: documentation = json.load(f) if not noUnion: print("from typing import Union") print("import sys") print("import types") print("_mock_data = {}") print("") with open(sys.argv[1]) as f: data = json.load(f) for method in data['result']['methods']: classes[method['func']['module']].append(method['func']) if "pv" not in classes: classes['pv'].append({'params': 'str', 'ret': 'xval', 'name': 'get'} ) classes['pv'].append({'params': 'str', 'ret': 'xval', 'name': 'gete'} ) classes['pv'].append({'params': 'str, int', 'ret': 'xval', 'name': 'getvn'} ) classes['pv'].append({'params': 'str, str', 'ret': 'xval', 'name': 'getvs'} ) classes['pv'].append({'params': 'str', 'ret': 'xval', 'name': 'getw'} ) classes['pv'].append({'params': 'str, int', 'ret': 'none', 'name': 'seti'} ) classes['pv'].append({'params': 'str, str', 'ret': 'none', 'name': 'sets'} ) classes['pv'].append({'params': 'str', 'ret': 'none', 'name': 'unset'} ) classes['pv'].append({'params': 'str', 'ret': 'none', 'name': 'is_null'} ) for module_name, module in classes.items(): if module_name != "": print("") print("class " + module_name.capitalize() + ":") for func in module: printFunction(module_name, func, 1) for func in classes['']: print("") printFunction('', func, 0) def document_module(module_name): if documentation is not None and module_name in documentation: print("\"\"\"") documentation_lines = documentation[module_name]["overview"].split("\n") for line in documentation_lines: print("" + line) print("\"\"\"") for module_name in classes.keys(): if module_name != "": if module_name in reserved_keywords: print("setattr(sys.modules[__name__], '" + module_name + "', " + module_name.capitalize() + "())") else: print(module_name + " = "+module_name.capitalize()+"()") document_module(module_name) print("") for module_name in classes.keys(): print("_mock_data['" + module_name + "'] = {}")