sc-oa 0.7.0.13__py3-none-any.whl → 0.7.0.14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sc-oa might be problematic. Click here for more details.

@@ -1,263 +1,263 @@
1
- """
2
- sphinxcontrib.openapi.openapi20
3
- -------------------------------
4
-
5
- The OpenAPI 2.0 (f.k.a. Swagger) spec renderer. Based on
6
- ``sphinxcontrib-httpdomain``.
7
-
8
- :copyright: (c) 2016, Ihor Kalnytskyi.
9
- :license: BSD, see LICENSE for details.
10
- """
11
-
12
- import collections
13
- import itertools
14
- import re
15
-
16
- from sphinxcontrib.openapi import utils
17
-
18
-
19
- def _httpresource(endpoint, method, properties, convert):
20
- parameters = properties.get('parameters', [])
21
- responses = properties['responses']
22
- indent = ' '
23
-
24
- yield '.. http:{0}:: {1}'.format(method, endpoint)
25
- yield ' :synopsis: {0}'.format(properties.get('summary', 'null'))
26
- yield ''
27
-
28
- if 'summary' in properties:
29
- for line in properties['summary'].splitlines():
30
- yield '{indent}**{line}**'.format(**locals())
31
- yield ''
32
-
33
- if 'description' in properties:
34
- for line in convert(properties['description']).splitlines():
35
- yield '{indent}{line}'.format(**locals())
36
- yield ''
37
-
38
- for param in filter(lambda p: p['in'] == 'path', parameters):
39
- yield indent + ':param {type} {name}:'.format(**param)
40
- for line in convert(param.get('description', '')).splitlines():
41
- yield '{indent}{indent}{line}'.format(**locals())
42
-
43
- # print request's query params
44
- for param in filter(lambda p: p['in'] == 'query', parameters):
45
- yield indent + ':query {type} {name}:'.format(**param)
46
- for line in convert(param.get('description', '')).splitlines():
47
- yield '{indent}{indent}{line}'.format(**locals())
48
-
49
- # print the json body params
50
- for param in filter(lambda p: p['in'] == 'body', parameters):
51
- if 'schema' in param:
52
- yield ''
53
- for line in convert_json_schema(param['schema']):
54
- yield '{indent}{line}'.format(**locals())
55
- yield ''
56
-
57
- # print response status codes
58
- for status, response in sorted(responses.items()):
59
- yield '{indent}:status {status}:'.format(**locals())
60
- for line in convert(response['description']).splitlines():
61
- yield '{indent}{indent}{line}'.format(**locals())
62
-
63
- # print request header params
64
- for param in filter(lambda p: p['in'] == 'header', parameters):
65
- yield indent + ':reqheader {name}:'.format(**param)
66
- for line in convert(param.get('description', '')).splitlines():
67
- yield '{indent}{indent}{line}'.format(**locals())
68
-
69
- # print response headers
70
- for status, response in responses.items():
71
- for headername, header in response.get('headers', {}).items():
72
- yield indent + ':resheader {name}:'.format(name=headername)
73
- for line in convert(header['description']).splitlines():
74
- yield '{indent}{indent}{line}'.format(**locals())
75
-
76
- for status, response in responses.items():
77
- if not is_2xx_response(status):
78
- continue
79
- if 'schema' in response:
80
- yield ''
81
- for line in convert_json_schema(
82
- response['schema'], directive=':>json'):
83
- yield '{indent}{line}'.format(**locals())
84
- yield ''
85
-
86
- yield ''
87
-
88
-
89
- def convert_json_schema(schema, directive=':<json'):
90
- """
91
- Convert json schema to `:<json` sphinx httpdomain.
92
- """
93
-
94
- output = []
95
-
96
- def _convert(schema, name='', required=False):
97
- """
98
- Fill the output list, with 2-tuple (name, template)
99
-
100
- i.e: ('user.age', 'str user.age: the age of user')
101
-
102
- This allow to sort output by field name
103
- """
104
-
105
- type_ = schema.get('type', 'any')
106
- required_properties = schema.get('required', ())
107
- if type_ == 'object' and schema.get('properties'):
108
- for prop, next_schema in schema.get('properties', {}).items():
109
- _convert(
110
- next_schema, '{name}.{prop}'.format(**locals()),
111
- (prop in required_properties))
112
-
113
- elif type_ == 'array':
114
- _convert(schema['items'], name + '[]')
115
-
116
- else:
117
- if name:
118
- name = name.lstrip('.')
119
- constraints = []
120
- if required:
121
- constraints.append('required')
122
- if schema.get('readOnly', False):
123
- constraints.append('read only')
124
- if constraints:
125
- constraints = '({})'.format(', '.join(constraints))
126
- else:
127
- constraints = ''
128
-
129
- if schema.get('description', ''):
130
- if constraints:
131
- output.append((
132
- name,
133
- '{type_} {name}:'
134
- ' {schema[description]}'
135
- ' {constraints}'.format(**locals())))
136
- else:
137
- output.append((
138
- name,
139
- '{type_} {name}:'
140
- ' {schema[description]}'.format(**locals())))
141
-
142
- else:
143
- if constraints:
144
- output.append(
145
- (name,
146
- '{type_} {name}:'
147
- ' {constraints}'.format(**locals())))
148
- else:
149
- output.append(
150
- (name,
151
- '{type_} {name}:'.format(**locals())))
152
-
153
- _convert(schema)
154
-
155
- for _, render in sorted(output):
156
- yield '{} {}'.format(directive, render)
157
-
158
-
159
- def is_2xx_response(status):
160
- try:
161
- status = int(status)
162
- return 200 <= status < 300
163
- except ValueError:
164
- pass
165
- return False
166
-
167
-
168
- def _header(title):
169
- yield title
170
- yield '=' * len(title)
171
- yield ''
172
-
173
-
174
- def openapihttpdomain(spec, **options):
175
- if 'examples' in options:
176
- raise ValueError(
177
- 'Rendering examples is not supported for OpenAPI v2.x specs.')
178
-
179
- if 'request' in options:
180
- raise ValueError(
181
- 'The :request: option is not supported for OpenAPI v2.x specs.')
182
-
183
- generators = []
184
-
185
- # OpenAPI spec may contain JSON references, common properties, etc.
186
- # Trying to render the spec "As Is" will require to put multiple
187
- # if-s around the code. In order to simplify flow, let's make the
188
- # spec to have only one (expected) schema, i.e. normalize it.
189
- utils.normalize_spec(spec, **options)
190
-
191
- # Paths list to be processed
192
- paths = []
193
-
194
- # If 'paths' are passed we've got to ensure they exist within an OpenAPI
195
- # spec; otherwise raise error and ask user to fix that.
196
- if 'paths' in options:
197
- if not set(options['paths']).issubset(spec['paths']):
198
- raise ValueError(
199
- 'One or more paths are not defined in the spec: %s.' % (
200
- ', '.join(set(options['paths']) - set(spec['paths'])),
201
- )
202
- )
203
- paths = options['paths']
204
-
205
- # Check against regular expressions to be included
206
- if 'include' in options:
207
- for i in options['include']:
208
- ir = re.compile(i)
209
- for path in spec['paths']:
210
- if ir.match(path):
211
- paths.append(path)
212
-
213
- # If no include nor paths option, then take full path
214
- if 'include' not in options and 'paths' not in options:
215
- paths = spec['paths']
216
-
217
- # Remove paths matching regexp
218
- if 'exclude' in options:
219
- _paths = []
220
- for e in options['exclude']:
221
- er = re.compile(e)
222
- for path in paths:
223
- if not er.match(path):
224
- _paths.append(path)
225
- paths = _paths
226
-
227
- if 'group' in options:
228
- groups = collections.OrderedDict(
229
- [(x['name'], []) for x in spec.get('tags', {})]
230
- )
231
-
232
- for endpoint in paths:
233
- for method, properties in spec['paths'][endpoint].items():
234
- if options.get('methods') and method not in options.get('methods'):
235
- continue
236
- key = properties.get('tags', [''])[0]
237
- groups.setdefault(key, []).append(_httpresource(
238
- endpoint,
239
- method,
240
- properties,
241
- utils.get_text_converter(options),
242
- ))
243
-
244
- for key in groups.keys():
245
- if key:
246
- generators.append(_header(key))
247
- else:
248
- generators.append(_header('default'))
249
-
250
- generators.extend(groups[key])
251
- else:
252
- for endpoint in paths:
253
- for method, properties in spec['paths'][endpoint].items():
254
- if options.get('methods') and method not in options.get('methods'):
255
- continue
256
- generators.append(_httpresource(
257
- endpoint,
258
- method,
259
- properties,
260
- utils.get_text_converter(options),
261
- ))
262
-
263
- return iter(itertools.chain(*generators))
1
+ """
2
+ sphinxcontrib.openapi.openapi20
3
+ -------------------------------
4
+
5
+ The OpenAPI 2.0 (f.k.a. Swagger) spec renderer. Based on
6
+ ``sphinxcontrib-httpdomain``.
7
+
8
+ :copyright: (c) 2016, Ihor Kalnytskyi.
9
+ :license: BSD, see LICENSE for details.
10
+ """
11
+
12
+ import collections
13
+ import itertools
14
+ import re
15
+
16
+ from sphinxcontrib.openapi import utils
17
+
18
+
19
+ def _httpresource(endpoint, method, properties, convert):
20
+ parameters = properties.get('parameters', [])
21
+ responses = properties['responses']
22
+ indent = ' '
23
+
24
+ yield '.. http:{0}:: {1}'.format(method, endpoint)
25
+ yield ' :synopsis: {0}'.format(properties.get('summary', 'null'))
26
+ yield ''
27
+
28
+ if 'summary' in properties:
29
+ for line in properties['summary'].splitlines():
30
+ yield '{indent}**{line}**'.format(**locals())
31
+ yield ''
32
+
33
+ if 'description' in properties:
34
+ for line in convert(properties['description']).splitlines():
35
+ yield '{indent}{line}'.format(**locals())
36
+ yield ''
37
+
38
+ for param in filter(lambda p: p['in'] == 'path', parameters):
39
+ yield indent + ':param {type} {name}:'.format(**param)
40
+ for line in convert(param.get('description', '')).splitlines():
41
+ yield '{indent}{indent}{line}'.format(**locals())
42
+
43
+ # print request's query params
44
+ for param in filter(lambda p: p['in'] == 'query', parameters):
45
+ yield indent + ':query {type} {name}:'.format(**param)
46
+ for line in convert(param.get('description', '')).splitlines():
47
+ yield '{indent}{indent}{line}'.format(**locals())
48
+
49
+ # print the json body params
50
+ for param in filter(lambda p: p['in'] == 'body', parameters):
51
+ if 'schema' in param:
52
+ yield ''
53
+ for line in convert_json_schema(param['schema']):
54
+ yield '{indent}{line}'.format(**locals())
55
+ yield ''
56
+
57
+ # print response status codes
58
+ for status, response in sorted(responses.items()):
59
+ yield '{indent}:status {status}:'.format(**locals())
60
+ for line in convert(response['description']).splitlines():
61
+ yield '{indent}{indent}{line}'.format(**locals())
62
+
63
+ # print request header params
64
+ for param in filter(lambda p: p['in'] == 'header', parameters):
65
+ yield indent + ':reqheader {name}:'.format(**param)
66
+ for line in convert(param.get('description', '')).splitlines():
67
+ yield '{indent}{indent}{line}'.format(**locals())
68
+
69
+ # print response headers
70
+ for status, response in responses.items():
71
+ for headername, header in response.get('headers', {}).items():
72
+ yield indent + ':resheader {name}:'.format(name=headername)
73
+ for line in convert(header['description']).splitlines():
74
+ yield '{indent}{indent}{line}'.format(**locals())
75
+
76
+ for status, response in responses.items():
77
+ if not is_2xx_response(status):
78
+ continue
79
+ if 'schema' in response:
80
+ yield ''
81
+ for line in convert_json_schema(
82
+ response['schema'], directive=':>json'):
83
+ yield '{indent}{line}'.format(**locals())
84
+ yield ''
85
+
86
+ yield ''
87
+
88
+
89
+ def convert_json_schema(schema, directive=':<json'):
90
+ """
91
+ Convert json schema to `:<json` sphinx httpdomain.
92
+ """
93
+
94
+ output = []
95
+
96
+ def _convert(schema, name='', required=False):
97
+ """
98
+ Fill the output list, with 2-tuple (name, template)
99
+
100
+ i.e: ('user.age', 'str user.age: the age of user')
101
+
102
+ This allow to sort output by field name
103
+ """
104
+
105
+ type_ = schema.get('type', 'any')
106
+ required_properties = schema.get('required', ())
107
+ if type_ == 'object' and schema.get('properties'):
108
+ for prop, next_schema in schema.get('properties', {}).items():
109
+ _convert(
110
+ next_schema, '{name}.{prop}'.format(**locals()),
111
+ (prop in required_properties))
112
+
113
+ elif type_ == 'array':
114
+ _convert(schema['items'], name + '[]')
115
+
116
+ else:
117
+ if name:
118
+ name = name.lstrip('.')
119
+ constraints = []
120
+ if required:
121
+ constraints.append('required')
122
+ if schema.get('readOnly', False):
123
+ constraints.append('read only')
124
+ if constraints:
125
+ constraints = '({})'.format(', '.join(constraints))
126
+ else:
127
+ constraints = ''
128
+
129
+ if schema.get('description', ''):
130
+ if constraints:
131
+ output.append((
132
+ name,
133
+ '{type_} {name}:'
134
+ ' {schema[description]}'
135
+ ' {constraints}'.format(**locals())))
136
+ else:
137
+ output.append((
138
+ name,
139
+ '{type_} {name}:'
140
+ ' {schema[description]}'.format(**locals())))
141
+
142
+ else:
143
+ if constraints:
144
+ output.append(
145
+ (name,
146
+ '{type_} {name}:'
147
+ ' {constraints}'.format(**locals())))
148
+ else:
149
+ output.append(
150
+ (name,
151
+ '{type_} {name}:'.format(**locals())))
152
+
153
+ _convert(schema)
154
+
155
+ for _, render in sorted(output):
156
+ yield '{} {}'.format(directive, render)
157
+
158
+
159
+ def is_2xx_response(status):
160
+ try:
161
+ status = int(status)
162
+ return 200 <= status < 300
163
+ except ValueError:
164
+ pass
165
+ return False
166
+
167
+
168
+ def _header(title):
169
+ yield title
170
+ yield '=' * len(title)
171
+ yield ''
172
+
173
+
174
+ def openapihttpdomain(spec, **options):
175
+ if 'examples' in options:
176
+ raise ValueError(
177
+ 'Rendering examples is not supported for OpenAPI v2.x specs.')
178
+
179
+ if 'request' in options:
180
+ raise ValueError(
181
+ 'The :request: option is not supported for OpenAPI v2.x specs.')
182
+
183
+ generators = []
184
+
185
+ # OpenAPI spec may contain JSON references, common properties, etc.
186
+ # Trying to render the spec "As Is" will require to put multiple
187
+ # if-s around the code. In order to simplify flow, let's make the
188
+ # spec to have only one (expected) schema, i.e. normalize it.
189
+ utils.normalize_spec(spec, **options)
190
+
191
+ # Paths list to be processed
192
+ paths = []
193
+
194
+ # If 'paths' are passed we've got to ensure they exist within an OpenAPI
195
+ # spec; otherwise raise error and ask user to fix that.
196
+ if 'paths' in options:
197
+ if not set(options['paths']).issubset(spec['paths']):
198
+ raise ValueError(
199
+ 'One or more paths are not defined in the spec: %s.' % (
200
+ ', '.join(set(options['paths']) - set(spec['paths'])),
201
+ )
202
+ )
203
+ paths = options['paths']
204
+
205
+ # Check against regular expressions to be included
206
+ if 'include' in options:
207
+ for i in options['include']:
208
+ ir = re.compile(i)
209
+ for path in spec['paths']:
210
+ if ir.match(path):
211
+ paths.append(path)
212
+
213
+ # If no include nor paths option, then take full path
214
+ if 'include' not in options and 'paths' not in options:
215
+ paths = spec['paths']
216
+
217
+ # Remove paths matching regexp
218
+ if 'exclude' in options:
219
+ _paths = []
220
+ for e in options['exclude']:
221
+ er = re.compile(e)
222
+ for path in paths:
223
+ if not er.match(path):
224
+ _paths.append(path)
225
+ paths = _paths
226
+
227
+ if 'group' in options:
228
+ groups = collections.OrderedDict(
229
+ [(x['name'], []) for x in spec.get('tags', {})]
230
+ )
231
+
232
+ for endpoint in paths:
233
+ for method, properties in spec['paths'][endpoint].items():
234
+ if options.get('methods') and method not in options.get('methods'):
235
+ continue
236
+ key = properties.get('tags', [''])[0]
237
+ groups.setdefault(key, []).append(_httpresource(
238
+ endpoint,
239
+ method,
240
+ properties,
241
+ utils.get_text_converter(options),
242
+ ))
243
+
244
+ for key in groups.keys():
245
+ if key:
246
+ generators.append(_header(key))
247
+ else:
248
+ generators.append(_header('default'))
249
+
250
+ generators.extend(groups[key])
251
+ else:
252
+ for endpoint in paths:
253
+ for method, properties in spec['paths'][endpoint].items():
254
+ if options.get('methods') and method not in options.get('methods'):
255
+ continue
256
+ generators.append(_httpresource(
257
+ endpoint,
258
+ method,
259
+ properties,
260
+ utils.get_text_converter(options),
261
+ ))
262
+
263
+ return iter(itertools.chain(*generators))