Source code for credmark.dto.dto_schema

from itertools import product


[docs]def combine_dict(dicts): dd = {} for d in dicts: dd |= d return dd
[docs]def cross_examples(*x, limit=10): return [combine_dict(ds) for ds in product(*x)][:limit]
# -> Union[Iterable[Tuple[Any, Any, Any]], Iterable[Dict[str, str]]]
[docs]def dto_schema_viz(head_node, # pylint: disable=too-many-arguments,too-many-locals,too-many-return-statements,too-many-branches,too-many-statements var_name, node, n_iter, ret_type, only_required, tag, limit=10): assert ret_type in ['tree', 'example'] # print(var_name, tag, ret_type, only_required) try: # pylint: disable=too-many-nested-blocks # 1. DTO/dict # 1.1 DTO with example # 1.2 DTO without example # 1.3 dict # 2. Array # 2.1 DTO # 2.2 other # 3. Union # 4. DTO Reference if 'type' in node: if node['type'] == 'object': # DTO with example if ret_type == 'example' and ('examples' in node or 'example' in node): # return [{var_name: v} for v in node.get('examples', node.get('example'))] return node.get('examples', [node.get('example')])[:limit] # DTO without example if ret_type == 'tree': ret = [(n_iter, var_name, node['type'])] else: ret = [{}] if 'properties' in node and len(node['properties']) > 0: props = node['properties'] required = node['required'] if 'required' in node else list( props.keys()) for prop_name, prop_item in props.items(): if only_required: if prop_name not in required: break drill_ret = dto_schema_viz( head_node, prop_name, prop_item, n_iter + 1, ret_type, only_required, 'prop', limit) if ret_type == 'tree': if len(ret) == 1: # For generic dict, return node['type'] which is "object". # For non-generic object type, return the object name. title_or_object = node['title'] if 'title' in node else node['type'] ret = [(n_iter, var_name, title_or_object + ('(*)' if prop_name in required else ''))] ret.extend(drill_ret) elif ret_type == 'example': if ret == [{var_name: node['type']}]: ret = drill_ret else: ret = cross_examples( ret, drill_ret, limit=limit) return ret if node['type'] == 'array': # array of object if '$ref' in node['items']: ref = node['items']['$ref'].split('/') definition_node = head_node[ref[1]][ref[2]] ret = dto_schema_viz(head_node, var_name, definition_node, n_iter, ret_type, only_required, 'array_ref', limit) if ret_type == 'tree': ret[0] = (*ret[0][:-1], f'List[{ref[2]}]') return ret return [{var_name: [x]} for x in ret][:limit] # array of other types array_type = node['items']['type'] if 'type' in node['items'] else 'Any' if 'items' in node['items']: array_type = ','.join([item['type'] for item in node['items']['items']]) array_type = f'({array_type})' if ret_type == 'tree': return [(n_iter, var_name, f'List[{array_type}]')] return [{var_name: f'[{array_type}]'}] # ['type'] != 'array' # ordinary type type_desc = node["type"] if 'enum' in node: q = "'" if type_desc == 'string' else '' vals = f"{q},{q}".join(node["enum"]) type_desc = f'{type_desc} [{q}{vals}{q}]' if ret_type == 'tree': return [(n_iter, var_name, type_desc)] return [{var_name: type_desc}] # Various Union type elif 'anyOf' in node or 'allOf' in node or 'oneOf' in node: ret = [] of_node = node.get('anyOf', node.get('allOf', node.get('oneOf'))) for item in of_node: drill_ret = dto_schema_viz(head_node, var_name, item, n_iter, ret_type, only_required, 'union', limit) if ret_type == 'tree': if len(ret) == 0: ret = drill_ret else: ret[0] = (ret[0][0], ret[0][1], ret[0][2] + # type: ignore ' | ' + drill_ret[0][2]) elif ret_type == 'example': if drill_ret == [{}]: drill_ret = [{var_name: '{}'}] if len(ret) == 0: ret = drill_ret else: for r in ret: for rr in drill_ret: for k, v in rr.items(): if k in r: r[var_name] = f'{r[var_name]} | {v}' else: r[var_name] = f'{r[var_name]} | {rr}' return ret # Object reference elif '$ref' in node: ref = node['$ref'].split('/') definition_node = head_node[ref[1]][ref[2]] if ret_type == 'example': # return [{var_name: dto_schema_viz(head_node, var_name, definition_node, # n_iter, ret_type, only_required, 'ref', limit)}] return [{var_name: v} for v in dto_schema_viz(head_node, var_name, definition_node, n_iter, ret_type, only_required, 'ref', limit)][:limit] return dto_schema_viz(head_node, var_name, definition_node, n_iter, ret_type, only_required, 'ref', limit) else: if ret_type == 'tree': return [(n_iter, var_name, 'object')] return [{var_name: 'object'}] except Exception as err: raise ValueError(f'Unknown schema node {var_name, node, err, tag}') from None