Repository navigation
Expand file tree
/
Copy pathgenerate_openapi_schema.py
More file actions
116 lines (87 loc) · 3.52 KB
/
Copy pathgenerate_openapi_schema.py
File metadata and controls
116 lines (87 loc) · 3.52 KB
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
"""Utility script to generate OpenAPI schema."""
import json
import pprint
import subprocess
import sys
from fastapi.openapi.utils import get_openapi
from client.ogx import AsyncOgxClientHolder
# it is needed to read proper configuration in order to start the app to generate schema
from configuration import configuration
CFG_FILE = "lightspeed-stack.yaml"
configuration.load_configuration(CFG_FILE)
# OGX client needs to be loaded before REST API is fully initialized
import asyncio # pylint: disable=C0411,C0413
asyncio.run(AsyncOgxClientHolder().load(configuration.configuration.ogx))
from app.main import app # pylint: disable=C0413
def read_version_from_openapi(openapi_filename: str) -> str:
"""
Extract the OpenAPI document's version from a generated OpenAPI JSON file.
Returns:
str: The value of the OpenAPI document's `info.version`.
"""
# retrieve pre-generated OpenAPI schema
with open(openapi_filename, encoding="utf-8") as fin:
pre_generated_schema = json.load(fin)
assert pre_generated_schema is not None
assert "info" in pre_generated_schema, "node 'info' not found in openapi.json"
info = pre_generated_schema["info"]
assert "version" in info, "node 'version' not found in 'info'"
return str(info["version"])
def read_version_from_pyproject() -> str:
"""
Obtain the project's version using PDM (`pdm show --version`), which supports dynamic versions.
Returns:
str: The project version string.
"""
# it is not safe to just try to read version from pyproject.toml file directly
# the PDM tool itself is able to retrieve the version, even if the version
# is generated dynamically
completed = subprocess.run(
["pdm", "show", "--version"],
capture_output=True,
check=True,
)
return completed.stdout.decode("utf-8").strip()
def generate_openapi_schema(schema_file_name: str) -> None:
"""Write the app's OpenAPI schema, then check its version against PDM.
Overwrites the named JSON file before checking versions; the file remains
if the check fails.
Raises:
AssertionError: If the schema and project versions differ.
subprocess.CalledProcessError: If ``pdm show --version`` fails.
OSError: If the file cannot be written or PDM cannot be started.
"""
print("Service metadata:")
print(app.title)
print(app.description)
print()
print("Routes:")
pprint.pprint(app.routes)
# retrieve OpenAPI schema via initialized app
open_api = get_openapi(
title=app.title,
summary=app.summary,
version=app.version,
openapi_version=app.openapi_version,
description=app.description,
routes=app.routes,
license_info=app.license_info,
servers=app.servers,
contact=app.contact,
tags=app.openapi_tags,
)
# dump the schema into file
with open(schema_file_name, "w", encoding="utf-8") as fout:
json.dump(open_api, fout, indent=4)
openapi_version = read_version_from_openapi(schema_file_name)
project_version = read_version_from_pyproject()
assert (
openapi_version == project_version
), f"OpenAPI version {openapi_version} != project version {project_version}"
print(f"OpenAPI schema generated into file {schema_file_name}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python generate_openapi_schema.py <filename>")
sys.exit(1)
filename = sys.argv[1]
generate_openapi_schema(filename)