1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
from typing import Any, Dict, List, Optional, Tuple, Union
from ..api.doc import SchemaInput, SchemaType
class EndpointDoc: # noqa: N802
DICT_TYPE = Union[Dict[str, Any], Dict[int, Any]]
def __init__(self, description: str = "", group: str = "",
parameters: Optional[Union[DICT_TYPE, List[Any], Tuple[Any, ...]]] = None,
responses: Optional[DICT_TYPE] = None) -> None:
self.description = description
self.group = group
self.parameters = parameters
self.responses = responses
self.validate_args()
if not self.parameters:
self.parameters = {} # type: ignore
self.resp = {}
if self.responses:
for status_code, response_body in self.responses.items():
schema_input = SchemaInput()
schema_input.type = SchemaType.ARRAY if \
isinstance(response_body, list) else SchemaType.OBJECT
schema_input.params = self._split_parameters(response_body)
self.resp[str(status_code)] = schema_input
def validate_args(self) -> None:
if not isinstance(self.description, str):
raise Exception("%s has been called with a description that is not a string: %s"
% (EndpointDoc.__name__, self.description))
if not isinstance(self.group, str):
raise Exception("%s has been called with a groupname that is not a string: %s"
% (EndpointDoc.__name__, self.group))
if self.parameters and not isinstance(self.parameters, dict):
raise Exception("%s has been called with parameters that is not a dict: %s"
% (EndpointDoc.__name__, self.parameters))
if self.responses and not isinstance(self.responses, dict):
raise Exception("%s has been called with responses that is not a dict: %s"
% (EndpointDoc.__name__, self.responses))
def _split_param(self, name: str, p_type: Union[type, DICT_TYPE, List[Any], Tuple[Any, ...]],
description: str, optional: bool = False, default_value: Any = None,
nested: bool = False) -> Dict[str, Any]:
param = {
'name': name,
'description': description,
'required': not optional,
'nested': nested,
}
if default_value:
param['default'] = default_value
if isinstance(p_type, type):
param['type'] = p_type
else:
nested_params = self._split_parameters(p_type, nested=True)
if nested_params:
param['type'] = type(p_type)
param['nested_params'] = nested_params
else:
param['type'] = p_type
return param
# Optional must be set to True in order to set default value and parameters format must be:
# 'name: (type or nested parameters, description, [optional], [default value])'
def _split_dict(self, data: DICT_TYPE, nested: bool) -> List[Any]:
splitted = []
for name, props in data.items():
if isinstance(name, str) and isinstance(props, tuple):
if len(props) == 2:
param = self._split_param(name, props[0], props[1], nested=nested)
elif len(props) == 3:
param = self._split_param(
name, props[0], props[1], optional=props[2], nested=nested)
if len(props) == 4:
param = self._split_param(name, props[0], props[1], props[2], props[3], nested)
splitted.append(param)
else:
raise Exception(
"""Parameter %s in %s has not correct format. Valid formats are:
<name>: (<type>, <description>, [optional], [default value])
<name>: (<[type]>, <description>, [optional], [default value])
<name>: (<[nested parameters]>, <description>, [optional], [default value])
<name>: (<{nested parameters}>, <description>, [optional], [default value])"""
% (name, EndpointDoc.__name__))
return splitted
def _split_list(self, data: Union[List[Any], Tuple[Any, ...]], nested: bool) -> List[Any]:
splitted = [] # type: List[Any]
for item in data:
splitted.extend(self._split_parameters(item, nested))
return splitted
# nested = True means parameters are inside a dict or array
def _split_parameters(self, data: Optional[Union[DICT_TYPE, List[Any], Tuple[Any, ...]]],
nested: bool = False) -> List[Any]:
param_list = [] # type: List[Any]
if isinstance(data, dict):
param_list.extend(self._split_dict(data, nested))
elif isinstance(data, (list, tuple)):
param_list.extend(self._split_list(data, True))
return param_list
def __call__(self, func: Any) -> Any:
func.doc_info = {
'summary': self.description,
'tag': self.group,
'parameters': self._split_parameters(self.parameters),
'response': self.resp
}
return func
class APIDoc(object):
def __init__(self, description="", group=""):
self.tag = group
self.tag_descr = description
def __call__(self, cls):
cls.doc_info = {
'tag': self.tag,
'tag_descr': self.tag_descr
}
return cls
|