-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathplugin.py
80 lines (54 loc) · 1.97 KB
/
plugin.py
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
""" Plugin class """
from pathlib import Path
from apispec import BasePlugin
from apispec.yaml_utils import load_operations_from_docstring
class FromFilePlugin(BasePlugin):
"""APISpec plugin for importing OpenAPI specifications from a file.
:param string func_key: the key used in `APISpec.path()` to register the
function name
"""
def __init__(self, func_key="view"):
super().__init__()
self.func_key = func_key
def operation_helper(self, path=None, operations=None, **kwargs):
""" apispec operation helper """
# get the endpoint name
view = kwargs.pop(self.func_key)
# get specs
specs = getattr(view, "__apispec__", None)
if specs is None:
get_specs = getattr(view, "__get_apispec__", None)
if get_specs is not None:
specs = get_specs()
# update operations
if specs is not None:
operations.update(specs)
def read_spec(path: str):
# get the file
path = Path(path)
if not path.exists():
return None
# get the content
return path.read_text()
def load_spec(func, path):
content = read_spec(path)
spec = func.__dict__.get("__previous_apispec__", {})
if content is None:
return spec
spec.update(load_operations_from_docstring(content))
func.___previous_apispec__ = spec
return spec
def from_file(spec_path, live_reload: bool = False):
""" Decorate an endpoint with an OpenAPI spec file to import. """
def wrapper(func):
# save the content in a special attribute of the function
content = read_spec(spec_path)
if content is None:
return func
if live_reload:
func.__get_apispec__ = lambda: load_spec(func, spec_path)
else:
func.__apispec__ = func.__dict__.get("__apispec__", {})
func.__apispec__.update(load_operations_from_docstring(content))
return func
return wrapper