0
# Utilities and YAML Support
1
2
Utility functions for OpenAPI reference building, docstring processing, dictionary manipulation, and YAML serialization with docstring parsing capabilities. These utilities support the core APISpec functionality and provide helpers for common OpenAPI operations.
3
4
## Capabilities
5
6
### Reference Building
7
8
Build OpenAPI reference objects for component linking and reusability.
9
10
```python { .api }
11
def build_reference(
12
component_type: str,
13
openapi_major_version: int,
14
component_name: str
15
) -> dict[str, str]:
16
"""
17
Build OpenAPI reference object for a component.
18
19
Parameters:
20
- component_type: Type of component ('schema', 'parameter', 'response', 'header', 'example', 'security_scheme')
21
- openapi_major_version: OpenAPI major version (2 or 3)
22
- component_name: Name of the component to reference
23
24
Returns:
25
Dictionary with $ref key pointing to the component location
26
27
Examples:
28
- OpenAPI 2.x: {"$ref": "#/definitions/User"}
29
- OpenAPI 3.x: {"$ref": "#/components/schemas/User"}
30
"""
31
```
32
33
### Docstring Processing
34
35
Process and clean docstrings for use in OpenAPI documentation.
36
37
```python { .api }
38
def trim_docstring(docstring: str) -> str:
39
"""
40
Uniformly trim leading/trailing whitespace from docstrings.
41
42
Parameters:
43
- docstring: Raw docstring text
44
45
Returns:
46
Cleaned docstring with consistent indentation removed
47
48
Based on PEP 257 docstring handling conventions.
49
"""
50
51
def dedent(content: str) -> str:
52
"""
53
Remove leading indent from a block of text.
54
55
Parameters:
56
- content: Text content with potential leading indentation
57
58
Returns:
59
Text with consistent leading indentation removed
60
61
Used for processing multiline docstrings and descriptions.
62
More robust than textwrap.dedent for mixed indentation patterns.
63
"""
64
```
65
66
### Dictionary Manipulation
67
68
Utility for deep dictionary updates and merging.
69
70
```python { .api }
71
def deepupdate(original: dict, update: dict) -> dict:
72
"""
73
Recursively update a dictionary without overwriting nested dictionaries.
74
75
Parameters:
76
- original: Original dictionary to update
77
- update: Dictionary containing updates
78
79
Returns:
80
Updated dictionary with deep merging of nested structures
81
82
Nested dictionaries are merged rather than replaced entirely.
83
"""
84
```
85
86
### YAML Serialization
87
88
Convert dictionaries to YAML format with OpenAPI-optimized settings.
89
90
```python { .api }
91
def dict_to_yaml(dic: dict, yaml_dump_kwargs: Any | None = None) -> str:
92
"""
93
Serialize dictionary to YAML string.
94
95
Parameters:
96
- dic: Dictionary to serialize
97
- yaml_dump_kwargs: Additional arguments passed to yaml.dump()
98
99
Returns:
100
YAML string representation
101
102
Default behavior preserves key ordering (sort_keys=False) to respect
103
schema field ordering in OpenAPI specifications.
104
"""
105
```
106
107
### Docstring YAML Parsing
108
109
Extract YAML content and OpenAPI operations from function docstrings.
110
111
```python { .api }
112
def load_yaml_from_docstring(docstring: str) -> dict:
113
"""
114
Load YAML content from docstring.
115
116
Parameters:
117
- docstring: Function or method docstring
118
119
Returns:
120
Dictionary parsed from YAML section of docstring
121
122
Looks for YAML content after '---' delimiter in docstring.
123
Returns empty dict if no YAML section found.
124
"""
125
126
def load_operations_from_docstring(docstring: str) -> dict:
127
"""
128
Extract OpenAPI operations from docstring YAML.
129
130
Parameters:
131
- docstring: Function or method docstring containing YAML
132
133
Returns:
134
Dictionary mapping HTTP methods to operation definitions
135
136
Filters YAML content to only include valid HTTP methods and x- extensions.
137
"""
138
```
139
140
## Constants
141
142
Configuration constants for OpenAPI specification structure.
143
144
```python { .api }
145
COMPONENT_SUBSECTIONS: dict[int, dict[str, str]] = {
146
2: {
147
"schema": "definitions",
148
"response": "responses",
149
"parameter": "parameters",
150
"security_scheme": "securityDefinitions"
151
},
152
3: {
153
"schema": "schemas",
154
"response": "responses",
155
"parameter": "parameters",
156
"header": "headers",
157
"example": "examples",
158
"security_scheme": "securitySchemes"
159
}
160
}
161
162
PATH_KEYS: set[str] = {"get", "put", "post", "delete", "options", "head", "patch"}
163
```
164
165
## Usage Examples
166
167
### Building References
168
169
```python
170
from apispec.utils import build_reference
171
172
# OpenAPI 3.x references
173
schema_ref = build_reference("schema", 3, "User")
174
# {"$ref": "#/components/schemas/User"}
175
176
param_ref = build_reference("parameter", 3, "UserId")
177
# {"$ref": "#/components/parameters/UserId"}
178
179
# OpenAPI 2.x references
180
schema_ref_v2 = build_reference("schema", 2, "User")
181
# {"$ref": "#/definitions/User"}
182
183
response_ref_v2 = build_reference("response", 2, "NotFound")
184
# {"$ref": "#/responses/NotFound"}
185
```
186
187
### Processing Docstrings
188
189
```python
190
from apispec.utils import trim_docstring, dedent
191
192
# Clean up docstring formatting
193
raw_docstring = '''
194
This is a function that does something important.
195
196
It has multiple lines with inconsistent indentation.
197
198
Returns:
199
Something useful
200
'''
201
202
cleaned = trim_docstring(raw_docstring)
203
# "This is a function that does something important.\n\n It has multiple lines with inconsistent indentation.\n\nReturns:\n Something useful"
204
205
dedented = dedent(cleaned)
206
# "This is a function that does something important.\n\nIt has multiple lines with inconsistent indentation.\n\nReturns:\nSomething useful"
207
```
208
209
### Dictionary Updates
210
211
```python
212
from apispec.utils import deepupdate
213
214
original = {
215
"info": {"title": "My API"},
216
"paths": {
217
"/users": {
218
"get": {"summary": "List users"}
219
}
220
}
221
}
222
223
update = {
224
"info": {"version": "1.0.0", "description": "API description"},
225
"paths": {
226
"/users": {
227
"post": {"summary": "Create user"}
228
}
229
}
230
}
231
232
result = deepupdate(original, update)
233
# {
234
# "info": {"title": "My API", "version": "1.0.0", "description": "API description"},
235
# "paths": {
236
# "/users": {
237
# "get": {"summary": "List users"},
238
# "post": {"summary": "Create user"}
239
# }
240
# }
241
# }
242
```
243
244
### YAML Operations
245
246
```python
247
from apispec.yaml_utils import dict_to_yaml, load_operations_from_docstring
248
249
# Convert specification to YAML
250
spec_dict = {"openapi": "3.0.2", "info": {"title": "API", "version": "1.0.0"}}
251
yaml_output = dict_to_yaml(spec_dict)
252
253
# Custom YAML formatting
254
yaml_sorted = dict_to_yaml(spec_dict, {"sort_keys": True, "indent": 4})
255
```
256
257
### Extracting Operations from Docstrings
258
259
```python
260
from apispec.yaml_utils import load_operations_from_docstring
261
262
def get_user(user_id):
263
"""Get user by ID.
264
---
265
get:
266
summary: Retrieve user information
267
parameters:
268
- name: user_id
269
in: path
270
required: true
271
schema:
272
type: integer
273
responses:
274
200:
275
description: User found
276
content:
277
application/json:
278
schema:
279
$ref: '#/components/schemas/User'
280
404:
281
description: User not found
282
"""
283
pass
284
285
# Extract operations from docstring
286
operations = load_operations_from_docstring(get_user.__doc__)
287
# {
288
# "get": {
289
# "summary": "Retrieve user information",
290
# "parameters": [...],
291
# "responses": {...}
292
# }
293
# }
294
295
# Use with APISpec
296
spec.path("/users/{user_id}", operations=operations)
297
```
298
299
### Framework Integration Helper
300
301
```python
302
from apispec.yaml_utils import load_operations_from_docstring
303
from apispec.utils import trim_docstring
304
305
def extract_openapi_from_view(view_function):
306
"""Helper to extract OpenAPI spec from framework view function."""
307
if not view_function.__doc__:
308
return {}
309
310
# Clean and parse docstring
311
cleaned_doc = trim_docstring(view_function.__doc__)
312
operations = load_operations_from_docstring(cleaned_doc)
313
314
# Add operation ID if not specified
315
for method, operation in operations.items():
316
operation.setdefault('operationId', f"{method}_{view_function.__name__}")
317
318
return operations
319
320
# Usage in framework plugin
321
class FrameworkPlugin(BasePlugin):
322
def operation_helper(self, path=None, operations=None, **kwargs):
323
view_function = kwargs.get('view_function')
324
if view_function and operations:
325
doc_operations = extract_openapi_from_view(view_function)
326
operations.update(doc_operations)
327
```
328
329
### Exception Classes
330
331
All utility functions may raise APISpec-related exceptions for error conditions.
332
333
```python { .api }
334
class APISpecError(Exception):
335
"""Base class for all apispec-related errors."""
336
337
class OpenAPIError(APISpecError):
338
"""Raised when OpenAPI spec validation fails."""
339
```