-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathexport_openapi.py
More file actions
99 lines (80 loc) · 2.87 KB
/
Copy pathexport_openapi.py
File metadata and controls
99 lines (80 loc) · 2.87 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
#!/usr/bin/env python3
"""
Export the flask-smorest OpenAPI spec to YAML/JSON.
Usage (from backend_api_python/):
python scripts/export_openapi.py
python scripts/export_openapi.py --output ../docs/api/openapi.yaml
python scripts/export_openapi.py --format json --output /tmp/openapi.json
Set SKIP_STARTUP_HOOKS=1 so workers and strategy restore are not started.
"""
from __future__ import annotations
import argparse
import json
import os
import sys
from pathlib import Path
# Repo layout: backend_api_python/scripts/export_openapi.py
_BACKEND_ROOT = Path(__file__).resolve().parents[1]
_REPO_ROOT = _BACKEND_ROOT.parent
_DEFAULT_OUTPUT = _REPO_ROOT / "docs" / "api" / "openapi.yaml"
sys.path.insert(0, str(_BACKEND_ROOT))
os.environ.setdefault("SKIP_STARTUP_HOOKS", "1")
os.environ.setdefault("SECRET_KEY", "openapi-export-dev-only-not-for-production")
os.environ.setdefault("OPENAPI_ENABLED", "false")
os.environ.setdefault("CACHE_ENABLED", "false")
def export_spec(output: Path, fmt: str) -> None:
import yaml
from app import create_app
from app.openapi import get_openapi_api
app = create_app()
api = get_openapi_api(app)
if api is None:
raise SystemExit("OpenAPI Api extension not registered")
with app.app_context():
spec_dict = api.spec.to_dict()
from app.openapi.register import enrich_spec
spec_dict = enrich_spec(spec_dict)
# Runtime build/version metadata is intentionally excluded from the
# committed spec. CI exports from branch refs while release images export
# from tags, so keeping this field would make openapi.yaml drift even when
# the API surface has not changed.
info = spec_dict.get("info")
if isinstance(info, dict):
info.pop("x-api-app-version", None)
output.parent.mkdir(parents=True, exist_ok=True)
if fmt == "yaml":
text = yaml.safe_dump(
spec_dict,
sort_keys=False,
allow_unicode=True,
default_flow_style=False,
)
output.write_text(text, encoding="utf-8")
elif fmt == "json":
output.write_text(
json.dumps(spec_dict, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8",
)
else:
raise SystemExit(f"Unsupported format: {fmt}")
print(f"Wrote OpenAPI {fmt.upper()} to {output}")
def main() -> None:
parser = argparse.ArgumentParser(description="Export QuantDinger Web API OpenAPI spec")
parser.add_argument(
"--output",
"-o",
type=Path,
default=_DEFAULT_OUTPUT,
help=f"Output file (default: {_DEFAULT_OUTPUT})",
)
parser.add_argument(
"--format",
"-f",
choices=("yaml", "json"),
default="yaml",
help="Serialization format (default: yaml)",
)
args = parser.parse_args()
export_spec(args.output, args.format)
if __name__ == "__main__":
main()