import inspect import re from typing import Annotated, get_type_hints from paramecio2.libraries.responsesapi import ListItem from settings import config wsgi_type='flask' if hasattr(config, 'wsgi_type'): wsgi_type=config.wsgi_type if wsgi_type=='flask': from flask import current_app #from app import app """ import app for key, view in app.app.view_functions.items(): #print(key) #print(url_for(key), key, view) if key.find('.')!=-1: #print(url_for(key)) print(rule, view) for rule in app.app.url_map.iter_rules(): print(rule.endpoint, rule) """ class AppDoc: def __init__(self, app, api_description): self.routes={} self.description=api_description self.tags={} self.components={} arr_apidocs=[] arr_components=[] rules={} if wsgi_type=='flask': for rule in current_app.url_map.iter_rules(): #print(rule.endpoint, rule) if rule.endpoint.startswith(app.name+'.'): rules[rule.endpoint]=rule #print(rules) for key, view in current_app.view_functions.items(): #print(app.name) #print(key) if key.startswith(app.name+'.'): #print(view.get_callback_args()) #if 'tag' in inspect.getmembers(view, lambda a:not(inspect.isroutine(a))): # print(key) if 'tag' in list(inspect.signature(view).parameters.keys()): route=re.sub(r'<\w+[:](\w+)?>', '{\\1}', rules[key].rule) #print(route) if 'GET' in rules[key].methods: method='get' if 'POST' in rules[key].methods: method='post' if 'PUT' in rules[key].methods: method='put' if 'DELETE' in rules[key].methods: method='delete' apidoc=ApiDoc(view, route, method, 'Action summary', 'Description') self.routes[key]=apidoc if not apidoc.tag in arr_apidocs: arr_apidocs.append(apidoc.tag) self.tags[apidoc.tag]=apidoc.tag.capitalize() if len(apidoc.component)>0: self.components.update(apidoc.component) type_hints=get_type_hints(view) if 'return' in type_hints: return_obj=type_hints['return'] name_comp=return_obj.__name__ self.components=get_fields(return_obj, name_comp, self.components) else: for entry in app.routes: #print(entry.args) # Function is added to doc api if tag inside if 'tag' in entry.get_callback_args(): route=re.sub(r'<(\w+)[:]?.*?>', '{\\1}', entry.rule) #print(entry.name) #routes.append({'route': orule, 'method': entry.method.lower(), 'api_description': api_description, 'tag': tag}) method=entry.method.lower() apidoc=ApiDoc(entry.callback, route, method, 'Action summary', 'Description') self.routes[entry.name]=apidoc #{'name': 'apidoc', 'description': 'apidoc description'} if not apidoc.tag in arr_apidocs: arr_apidocs.append(apidoc.tag) self.tags[apidoc.tag]=apidoc.tag.capitalize() if len(apidoc.component)>0: #print(apidoc.component) self.components.update(apidoc.component) #if not apidoc.components # Get return from route function called entry.callback type_hints=get_type_hints(entry.callback) if 'return' in type_hints: return_obj=type_hints['return'] name_comp=return_obj.__name__ #fields_return=inspect.getmembers(return_obj, lambda a:not(inspect.isroutine(a))) self.components=get_fields(return_obj, name_comp, self.components) def get_fields(return_obj, name_comp, components): if not name_comp in components and name_comp!='StandardResponse': components[name_comp]={} fields_return=inspect.getmembers(return_obj, lambda a:not(inspect.isroutine(a))) for f in [field for field in fields_return if not field[0].startswith('__')]: name_prop=f[0] if type(f[1]).__bases__[0] is not ListItem: components[name_comp][name_prop]={} components[name_comp][name_prop]['type']=getattr(f[1], 'jtype') try: components[name_comp][name_prop]['format']=getattr(f[1], 'jformat') except AttributeError: components[name_comp][name_prop]['format']='' try: components[name_comp][name_prop]['example']=getattr(f[1], 'jexample') except AttributeError: components[name_comp][name_prop]['example']='' else: #components=get_fields(f[1] components[name_comp][name_prop]={} components[name_comp][name_prop]['type']='array' name_comp_sub=type(f[1]).__name__ components[name_comp][name_prop]['object']=name_comp_sub components=get_fields(f[1], name_comp_sub, components) pass return components #print(self.tags) class ApiDoc: def __init__(self, func_api, route, method, summary, description): self.route=route self.method=method self.summary=summary self.description=description #self.tag_name=tag_name self.operationId="".join([f.capitalize() for f in func_api.__name__.split('_')]) self.parameters=[] self.tag='' self.bearer=False self.post={} sign=inspect.signature(func_api) # The return object self.return_obj=None self.component={} #if hasattr(sign, 'return_annotation'): if sign.return_annotation.__name__!='_empty': self.return_obj=sign.return_annotation.__name__ #print(self.return_obj) args=inspect.getfullargspec(func_api) annotations=func_api.__annotations__ # The parameters #print(annotations) params=sign.parameters #print(params) args_len=len(tuple(re.finditer(r'\{(\w+)[:]?.*?\}', route))) #print(args_len) z=0 for k, f in params.items(): if k!='tag' and k!='post' and z