|
11 | 11 | from __future__ import annotations |
12 | 12 |
|
13 | 13 | import re |
| 14 | +import tomllib |
14 | 15 | from http import HTTPStatus |
| 16 | +from pathlib import Path |
15 | 17 | from typing import Any |
16 | 18 |
|
17 | 19 | from fastapi import FastAPI |
|
31 | 33 | _HTTP_METHODS = {"get", "post", "put", "patch", "delete", "options", "head", "trace"} |
32 | 34 | _STEP_PATTERN = r"^[1-9][0-9]*[smhd]$" |
33 | 35 | _STANDARD_ERROR_CODES = {"400", "401", "403", "404", "429", "500", "502", "503"} |
| 36 | +_DEFAULT_APP_VERSION = "0.0.1" |
| 37 | + |
| 38 | + |
| 39 | +def _project_version() -> str: |
| 40 | + pyproject_path = Path(__file__).resolve().parents[1] / "pyproject.toml" |
| 41 | + try: |
| 42 | + project = tomllib.loads(pyproject_path.read_text(encoding="utf-8")).get("project", {}) |
| 43 | + except (OSError, tomllib.TOMLDecodeError): |
| 44 | + return _DEFAULT_APP_VERSION |
| 45 | + version = project.get("version") |
| 46 | + return version if isinstance(version, str) and version.strip() else _DEFAULT_APP_VERSION |
34 | 47 |
|
35 | 48 |
|
36 | 49 | def _status_description(status_code: int) -> str: |
@@ -264,6 +277,9 @@ def custom_openapi() -> Any: |
264 | 277 | if not isinstance(schema_value, dict): |
265 | 278 | return schema_value |
266 | 279 | schema = schema_value |
| 280 | + info = schema.get("info") |
| 281 | + if isinstance(info, dict): |
| 282 | + info["version"] = _project_version() |
267 | 283 |
|
268 | 284 | _ensure_security_schemes(schema) |
269 | 285 | _ensure_error_schema(schema) |
|
0 commit comments