vega-framework 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vega_framework-0.2.1 → vega_framework-0.2.2}/PKG-INFO +1 -1
- {vega_framework-0.2.1 → vega_framework-0.2.2}/pyproject.toml +1 -1
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/__init__.py +8 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/application.py +63 -0
- vega_framework-0.2.2/vega/web/docs.py +104 -0
- vega_framework-0.2.2/vega/web/openapi.py +292 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/LICENSE +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/README.md +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/commands/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/commands/add.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/commands/generate.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/commands/init.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/commands/migrate.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/commands/update.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/commands/web.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/main.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/scaffolds/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/scaffolds/fastapi.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/scaffolds/sqlalchemy.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/scaffolds/vega_web.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/cli/command.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/cli/command_simple.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/cli/commands_init.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/components.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/entity.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/event.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/event_handler.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/interactor.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/mediator.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/repository_interface.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/service_interface.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/infrastructure/model.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/infrastructure/repository_impl.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/infrastructure/service_impl.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/loader.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/.env.example +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/.gitignore +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/ARCHITECTURE.md.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/README.md.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/config.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/events_init.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/main.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/main_fastapi.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/main_standard.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/pyproject.toml.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/settings.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/sqlalchemy/alembic.ini.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/sqlalchemy/database_manager.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/sqlalchemy/env.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/sqlalchemy/script.py.mako +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/__init__.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/app.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/health_route.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/main.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/middleware.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/models_init.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/request_model.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/response_model.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/router.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/routes_init.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/routes_init_autodiscovery.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/user_models.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/users_route.py.j2 +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/utils/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/utils/async_support.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/utils/messages.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/utils/naming.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/utils/validators.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/di/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/di/container.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/di/decorators.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/di/errors.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/di/scope.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/discovery/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/discovery/commands.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/discovery/events.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/discovery/routes.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/events/README.md +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/events/SYNTAX_GUIDE.md +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/events/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/events/bus.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/events/decorators.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/events/event.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/events/middleware.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/patterns/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/patterns/interactor.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/patterns/mediator.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/patterns/repository.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/patterns/service.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/settings/__init__.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/settings/base.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/builtin_middlewares.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/exceptions.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/middleware.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/request.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/response.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/route_middleware.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/router.py +0 -0
- {vega_framework-0.2.1 → vega_framework-0.2.2}/vega/web/routing.py +0 -0
@@ -66,6 +66,10 @@ from .route_middleware import (
|
|
66
66
|
middleware,
|
67
67
|
)
|
68
68
|
|
69
|
+
# OpenAPI / Documentation
|
70
|
+
from .openapi import get_openapi_schema
|
71
|
+
from .docs import get_swagger_ui_html, get_redoc_html
|
72
|
+
|
69
73
|
__all__ = [
|
70
74
|
# Version
|
71
75
|
"__version__",
|
@@ -97,4 +101,8 @@ __all__ = [
|
|
97
101
|
"RouteMiddleware",
|
98
102
|
"MiddlewarePhase",
|
99
103
|
"middleware",
|
104
|
+
# OpenAPI / Docs
|
105
|
+
"get_openapi_schema",
|
106
|
+
"get_swagger_ui_html",
|
107
|
+
"get_redoc_html",
|
100
108
|
]
|
@@ -7,10 +7,13 @@ from starlette.middleware import Middleware
|
|
7
7
|
from starlette.middleware.cors import CORSMiddleware
|
8
8
|
from starlette.routing import Mount, Route as StarletteRoute
|
9
9
|
from starlette.types import ASGIApp
|
10
|
+
from starlette.responses import JSONResponse as StarletteJSONResponse
|
10
11
|
|
11
12
|
from .router import Router
|
12
13
|
from .exceptions import HTTPException
|
13
14
|
from .response import JSONResponse
|
15
|
+
from .openapi import get_openapi_schema
|
16
|
+
from .docs import get_swagger_ui_html, get_redoc_html
|
14
17
|
|
15
18
|
|
16
19
|
class VegaApp:
|
@@ -59,12 +62,20 @@ class VegaApp:
|
|
59
62
|
middleware: Optional[Sequence[Middleware]] = None,
|
60
63
|
on_startup: Optional[Sequence[Callable]] = None,
|
61
64
|
on_shutdown: Optional[Sequence[Callable]] = None,
|
65
|
+
docs_url: Optional[str] = "/docs",
|
66
|
+
redoc_url: Optional[str] = "/redoc",
|
67
|
+
openapi_url: Optional[str] = "/openapi.json",
|
62
68
|
):
|
63
69
|
self.title = title
|
64
70
|
self.description = description
|
65
71
|
self.version = version
|
66
72
|
self.debug = debug
|
67
73
|
|
74
|
+
# Documentation URLs (None to disable)
|
75
|
+
self.docs_url = docs_url
|
76
|
+
self.redoc_url = redoc_url
|
77
|
+
self.openapi_url = openapi_url
|
78
|
+
|
68
79
|
# Internal router for top-level routes
|
69
80
|
self._router = Router()
|
70
81
|
|
@@ -78,6 +89,9 @@ class VegaApp:
|
|
78
89
|
# Starlette app (created lazily)
|
79
90
|
self._starlette_app: Optional[Starlette] = None
|
80
91
|
|
92
|
+
# OpenAPI schema (cached)
|
93
|
+
self._openapi_schema: Optional[Dict[str, Any]] = None
|
94
|
+
|
81
95
|
def add_middleware(
|
82
96
|
self,
|
83
97
|
middleware_class: type,
|
@@ -197,6 +211,22 @@ class VegaApp:
|
|
197
211
|
"""
|
198
212
|
return self._router.route(path, methods, **kwargs)
|
199
213
|
|
214
|
+
def openapi(self) -> Dict[str, Any]:
|
215
|
+
"""
|
216
|
+
Generate and return the OpenAPI schema.
|
217
|
+
|
218
|
+
Returns:
|
219
|
+
OpenAPI schema dictionary
|
220
|
+
"""
|
221
|
+
if self._openapi_schema is None:
|
222
|
+
self._openapi_schema = get_openapi_schema(
|
223
|
+
title=self.title,
|
224
|
+
version=self.version,
|
225
|
+
description=self.description,
|
226
|
+
routes=self._router.get_routes(),
|
227
|
+
)
|
228
|
+
return self._openapi_schema
|
229
|
+
|
200
230
|
def _build_starlette_app(self) -> Starlette:
|
201
231
|
"""Build the Starlette application from routes and middleware."""
|
202
232
|
# Convert Vega routes to Starlette routes
|
@@ -204,6 +234,39 @@ class VegaApp:
|
|
204
234
|
route.to_starlette_route() for route in self._router.get_routes()
|
205
235
|
]
|
206
236
|
|
237
|
+
# Add OpenAPI endpoint
|
238
|
+
if self.openapi_url:
|
239
|
+
async def openapi_endpoint(request):
|
240
|
+
return StarletteJSONResponse(self.openapi())
|
241
|
+
|
242
|
+
starlette_routes.append(
|
243
|
+
StarletteRoute(self.openapi_url, endpoint=openapi_endpoint, methods=["GET"])
|
244
|
+
)
|
245
|
+
|
246
|
+
# Add Swagger UI endpoint
|
247
|
+
if self.docs_url:
|
248
|
+
async def swagger_ui_endpoint(request):
|
249
|
+
return get_swagger_ui_html(
|
250
|
+
openapi_url=self.openapi_url or "/openapi.json",
|
251
|
+
title=f"{self.title} - Swagger UI"
|
252
|
+
)
|
253
|
+
|
254
|
+
starlette_routes.append(
|
255
|
+
StarletteRoute(self.docs_url, endpoint=swagger_ui_endpoint, methods=["GET"])
|
256
|
+
)
|
257
|
+
|
258
|
+
# Add ReDoc endpoint
|
259
|
+
if self.redoc_url:
|
260
|
+
async def redoc_endpoint(request):
|
261
|
+
return get_redoc_html(
|
262
|
+
openapi_url=self.openapi_url or "/openapi.json",
|
263
|
+
title=f"{self.title} - ReDoc"
|
264
|
+
)
|
265
|
+
|
266
|
+
starlette_routes.append(
|
267
|
+
StarletteRoute(self.redoc_url, endpoint=redoc_endpoint, methods=["GET"])
|
268
|
+
)
|
269
|
+
|
207
270
|
# Create Starlette app
|
208
271
|
app = Starlette(
|
209
272
|
debug=self.debug,
|
@@ -0,0 +1,104 @@
|
|
1
|
+
"""Documentation endpoints for Vega Web Framework"""
|
2
|
+
|
3
|
+
from typing import Callable
|
4
|
+
from starlette.responses import HTMLResponse, JSONResponse
|
5
|
+
|
6
|
+
|
7
|
+
def get_swagger_ui_html(
|
8
|
+
*,
|
9
|
+
openapi_url: str,
|
10
|
+
title: str,
|
11
|
+
swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
|
12
|
+
swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
|
13
|
+
swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
|
14
|
+
) -> HTMLResponse:
|
15
|
+
"""
|
16
|
+
Generate Swagger UI HTML page.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
openapi_url: URL to OpenAPI schema JSON
|
20
|
+
title: Page title
|
21
|
+
swagger_js_url: URL to Swagger UI JavaScript
|
22
|
+
swagger_css_url: URL to Swagger UI CSS
|
23
|
+
swagger_favicon_url: URL to favicon
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
HTML response with Swagger UI
|
27
|
+
"""
|
28
|
+
html = f"""
|
29
|
+
<!DOCTYPE html>
|
30
|
+
<html>
|
31
|
+
<head>
|
32
|
+
<title>{title}</title>
|
33
|
+
<meta charset="utf-8"/>
|
34
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
35
|
+
<link rel="shortcut icon" href="{swagger_favicon_url}">
|
36
|
+
<link rel="stylesheet" type="text/css" href="{swagger_css_url}" />
|
37
|
+
</head>
|
38
|
+
<body>
|
39
|
+
<div id="swagger-ui"></div>
|
40
|
+
<script src="{swagger_js_url}"></script>
|
41
|
+
<script>
|
42
|
+
const ui = SwaggerUIBundle({{
|
43
|
+
url: '{openapi_url}',
|
44
|
+
dom_id: '#swagger-ui',
|
45
|
+
presets: [
|
46
|
+
SwaggerUIBundle.presets.apis,
|
47
|
+
SwaggerUIBundle.SwaggerUIStandalonePreset
|
48
|
+
],
|
49
|
+
layout: "BaseLayout",
|
50
|
+
deepLinking: true,
|
51
|
+
showExtensions: true,
|
52
|
+
showCommonExtensions: true
|
53
|
+
}})
|
54
|
+
</script>
|
55
|
+
</body>
|
56
|
+
</html>
|
57
|
+
"""
|
58
|
+
return HTMLResponse(content=html)
|
59
|
+
|
60
|
+
|
61
|
+
def get_redoc_html(
|
62
|
+
*,
|
63
|
+
openapi_url: str,
|
64
|
+
title: str,
|
65
|
+
redoc_js_url: str = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
|
66
|
+
redoc_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
|
67
|
+
) -> HTMLResponse:
|
68
|
+
"""
|
69
|
+
Generate ReDoc HTML page.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
openapi_url: URL to OpenAPI schema JSON
|
73
|
+
title: Page title
|
74
|
+
redoc_js_url: URL to ReDoc JavaScript
|
75
|
+
redoc_favicon_url: URL to favicon
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
HTML response with ReDoc
|
79
|
+
"""
|
80
|
+
html = f"""
|
81
|
+
<!DOCTYPE html>
|
82
|
+
<html>
|
83
|
+
<head>
|
84
|
+
<title>{title}</title>
|
85
|
+
<meta charset="utf-8"/>
|
86
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
87
|
+
<link rel="shortcut icon" href="{redoc_favicon_url}">
|
88
|
+
<style>
|
89
|
+
body {{
|
90
|
+
margin: 0;
|
91
|
+
padding: 0;
|
92
|
+
}}
|
93
|
+
</style>
|
94
|
+
</head>
|
95
|
+
<body>
|
96
|
+
<redoc spec-url="{openapi_url}"></redoc>
|
97
|
+
<script src="{redoc_js_url}"></script>
|
98
|
+
</body>
|
99
|
+
</html>
|
100
|
+
"""
|
101
|
+
return HTMLResponse(content=html)
|
102
|
+
|
103
|
+
|
104
|
+
__all__ = ["get_swagger_ui_html", "get_redoc_html"]
|
@@ -0,0 +1,292 @@
|
|
1
|
+
"""OpenAPI schema generation for Vega Web Framework"""
|
2
|
+
|
3
|
+
from typing import Any, Dict, List, Optional, Type, get_type_hints
|
4
|
+
from inspect import signature, Parameter
|
5
|
+
import json
|
6
|
+
|
7
|
+
try:
|
8
|
+
from pydantic import BaseModel
|
9
|
+
PYDANTIC_AVAILABLE = True
|
10
|
+
except ImportError:
|
11
|
+
PYDANTIC_AVAILABLE = False
|
12
|
+
BaseModel = None # type: ignore
|
13
|
+
|
14
|
+
|
15
|
+
def get_openapi_schema(
|
16
|
+
*,
|
17
|
+
title: str,
|
18
|
+
version: str,
|
19
|
+
description: str = "",
|
20
|
+
routes: List[Any],
|
21
|
+
openapi_version: str = "3.0.2",
|
22
|
+
) -> Dict[str, Any]:
|
23
|
+
"""
|
24
|
+
Generate OpenAPI 3.0 schema from routes.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
title: API title
|
28
|
+
version: API version
|
29
|
+
description: API description
|
30
|
+
routes: List of Route objects
|
31
|
+
openapi_version: OpenAPI specification version
|
32
|
+
|
33
|
+
Returns:
|
34
|
+
OpenAPI schema dictionary
|
35
|
+
"""
|
36
|
+
schema: Dict[str, Any] = {
|
37
|
+
"openapi": openapi_version,
|
38
|
+
"info": {
|
39
|
+
"title": title,
|
40
|
+
"version": version,
|
41
|
+
},
|
42
|
+
"paths": {},
|
43
|
+
}
|
44
|
+
|
45
|
+
if description:
|
46
|
+
schema["info"]["description"] = description
|
47
|
+
|
48
|
+
# Components for reusable schemas
|
49
|
+
components: Dict[str, Any] = {
|
50
|
+
"schemas": {}
|
51
|
+
}
|
52
|
+
|
53
|
+
# Process each route
|
54
|
+
for route in routes:
|
55
|
+
path = route.path
|
56
|
+
|
57
|
+
# Convert path parameters from {param} to OpenAPI format
|
58
|
+
openapi_path = path
|
59
|
+
|
60
|
+
if openapi_path not in schema["paths"]:
|
61
|
+
schema["paths"][openapi_path] = {}
|
62
|
+
|
63
|
+
for method in route.methods:
|
64
|
+
method_lower = method.lower()
|
65
|
+
|
66
|
+
operation: Dict[str, Any] = {
|
67
|
+
"responses": {
|
68
|
+
"200": {
|
69
|
+
"description": "Successful Response"
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
# Add summary and description
|
75
|
+
if route.summary:
|
76
|
+
operation["summary"] = route.summary
|
77
|
+
|
78
|
+
if route.description:
|
79
|
+
operation["description"] = route.description
|
80
|
+
elif route.endpoint.__doc__:
|
81
|
+
operation["description"] = route.endpoint.__doc__.strip()
|
82
|
+
|
83
|
+
# Add tags
|
84
|
+
if route.tags:
|
85
|
+
operation["tags"] = route.tags
|
86
|
+
|
87
|
+
# Add operation ID
|
88
|
+
operation["operationId"] = f"{method_lower}_{route.name or route.endpoint.__name__}"
|
89
|
+
|
90
|
+
# Analyze endpoint parameters
|
91
|
+
params = _get_parameters(route)
|
92
|
+
if params:
|
93
|
+
operation["parameters"] = params
|
94
|
+
|
95
|
+
# Analyze request body
|
96
|
+
request_body = _get_request_body(route)
|
97
|
+
if request_body:
|
98
|
+
operation["requestBody"] = request_body
|
99
|
+
# Add request body schemas to components
|
100
|
+
if PYDANTIC_AVAILABLE and "content" in request_body:
|
101
|
+
for content_type, content_schema in request_body["content"].items():
|
102
|
+
if "schema" in content_schema and "$ref" in content_schema["schema"]:
|
103
|
+
model_name = content_schema["schema"]["$ref"].split("/")[-1]
|
104
|
+
# Model will be added when processing response_model
|
105
|
+
|
106
|
+
# Analyze response model
|
107
|
+
if route.response_model:
|
108
|
+
response_schema = _get_response_schema(route.response_model, components)
|
109
|
+
if response_schema:
|
110
|
+
operation["responses"]["200"] = {
|
111
|
+
"description": "Successful Response",
|
112
|
+
"content": {
|
113
|
+
"application/json": {
|
114
|
+
"schema": response_schema
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
# Add status code if specified
|
120
|
+
if route.status_code and route.status_code != 200:
|
121
|
+
operation["responses"][str(route.status_code)] = operation["responses"].pop("200")
|
122
|
+
|
123
|
+
# Add error responses
|
124
|
+
operation["responses"]["422"] = {
|
125
|
+
"description": "Validation Error"
|
126
|
+
}
|
127
|
+
|
128
|
+
schema["paths"][openapi_path][method_lower] = operation
|
129
|
+
|
130
|
+
# Add components if we have any schemas
|
131
|
+
if components["schemas"]:
|
132
|
+
schema["components"] = components
|
133
|
+
|
134
|
+
return schema
|
135
|
+
|
136
|
+
|
137
|
+
def _get_parameters(route: Any) -> List[Dict[str, Any]]:
|
138
|
+
"""Extract path and query parameters from route."""
|
139
|
+
parameters = []
|
140
|
+
|
141
|
+
# Get function signature
|
142
|
+
sig = signature(route.endpoint)
|
143
|
+
type_hints = get_type_hints(route.endpoint)
|
144
|
+
|
145
|
+
# Find which parameters are Pydantic models (request body)
|
146
|
+
request_body_params = set()
|
147
|
+
if PYDANTIC_AVAILABLE:
|
148
|
+
for param_name, param in sig.parameters.items():
|
149
|
+
param_type = type_hints.get(param_name)
|
150
|
+
if param_type and isinstance(param_type, type) and issubclass(param_type, BaseModel):
|
151
|
+
request_body_params.add(param_name)
|
152
|
+
|
153
|
+
for param_name, param in sig.parameters.items():
|
154
|
+
# Skip special parameters
|
155
|
+
if param_name in ("request", "self", "cls"):
|
156
|
+
continue
|
157
|
+
|
158
|
+
# Skip parameters that are Pydantic models (they're in request body)
|
159
|
+
if param_name in request_body_params:
|
160
|
+
continue
|
161
|
+
|
162
|
+
# Check if it's a path parameter
|
163
|
+
if f"{{{param_name}}}" in route.path:
|
164
|
+
param_schema = {
|
165
|
+
"name": param_name,
|
166
|
+
"in": "path",
|
167
|
+
"required": True,
|
168
|
+
"schema": _get_type_schema(type_hints.get(param_name, str))
|
169
|
+
}
|
170
|
+
parameters.append(param_schema)
|
171
|
+
elif param.default == Parameter.empty:
|
172
|
+
# Required query parameter
|
173
|
+
param_schema = {
|
174
|
+
"name": param_name,
|
175
|
+
"in": "query",
|
176
|
+
"required": True,
|
177
|
+
"schema": _get_type_schema(type_hints.get(param_name, str))
|
178
|
+
}
|
179
|
+
parameters.append(param_schema)
|
180
|
+
else:
|
181
|
+
# Optional query parameter
|
182
|
+
param_schema = {
|
183
|
+
"name": param_name,
|
184
|
+
"in": "query",
|
185
|
+
"required": False,
|
186
|
+
"schema": _get_type_schema(type_hints.get(param_name, str))
|
187
|
+
}
|
188
|
+
if param.default is not None and param.default != Parameter.empty:
|
189
|
+
param_schema["schema"]["default"] = param.default
|
190
|
+
parameters.append(param_schema)
|
191
|
+
|
192
|
+
return parameters
|
193
|
+
|
194
|
+
|
195
|
+
def _get_request_body(route: Any) -> Optional[Dict[str, Any]]:
|
196
|
+
"""Extract request body schema from route."""
|
197
|
+
if not PYDANTIC_AVAILABLE:
|
198
|
+
return None
|
199
|
+
|
200
|
+
# Get function signature
|
201
|
+
sig = signature(route.endpoint)
|
202
|
+
type_hints = get_type_hints(route.endpoint)
|
203
|
+
|
204
|
+
for param_name, param in sig.parameters.items():
|
205
|
+
# Skip special parameters and path parameters
|
206
|
+
if param_name in ("request", "self", "cls"):
|
207
|
+
continue
|
208
|
+
if f"{{{param_name}}}" in route.path:
|
209
|
+
continue
|
210
|
+
|
211
|
+
param_type = type_hints.get(param_name)
|
212
|
+
|
213
|
+
# Check if it's a Pydantic model
|
214
|
+
if param_type and isinstance(param_type, type) and issubclass(param_type, BaseModel):
|
215
|
+
model_schema = param_type.model_json_schema()
|
216
|
+
model_name = param_type.__name__
|
217
|
+
|
218
|
+
return {
|
219
|
+
"required": True,
|
220
|
+
"content": {
|
221
|
+
"application/json": {
|
222
|
+
"schema": {
|
223
|
+
"$ref": f"#/components/schemas/{model_name}"
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
return None
|
230
|
+
|
231
|
+
|
232
|
+
def _get_response_schema(response_model: Type, components: Dict[str, Any]) -> Dict[str, Any]:
|
233
|
+
"""Get response schema from response model."""
|
234
|
+
if not PYDANTIC_AVAILABLE:
|
235
|
+
return {}
|
236
|
+
|
237
|
+
# Handle Pydantic models
|
238
|
+
if isinstance(response_model, type) and issubclass(response_model, BaseModel):
|
239
|
+
model_name = response_model.__name__
|
240
|
+
|
241
|
+
# Add model schema to components
|
242
|
+
if model_name not in components["schemas"]:
|
243
|
+
components["schemas"][model_name] = response_model.model_json_schema()
|
244
|
+
|
245
|
+
return {
|
246
|
+
"$ref": f"#/components/schemas/{model_name}"
|
247
|
+
}
|
248
|
+
|
249
|
+
# Handle List types
|
250
|
+
if hasattr(response_model, "__origin__"):
|
251
|
+
if response_model.__origin__ is list:
|
252
|
+
item_type = response_model.__args__[0]
|
253
|
+
if isinstance(item_type, type) and issubclass(item_type, BaseModel):
|
254
|
+
model_name = item_type.__name__
|
255
|
+
|
256
|
+
# Add model schema to components
|
257
|
+
if model_name not in components["schemas"]:
|
258
|
+
components["schemas"][model_name] = item_type.model_json_schema()
|
259
|
+
|
260
|
+
return {
|
261
|
+
"type": "array",
|
262
|
+
"items": {
|
263
|
+
"$ref": f"#/components/schemas/{model_name}"
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
# Handle dict
|
268
|
+
if response_model is dict:
|
269
|
+
return {"type": "object"}
|
270
|
+
|
271
|
+
return {}
|
272
|
+
|
273
|
+
|
274
|
+
def _get_type_schema(param_type: Any) -> Dict[str, Any]:
|
275
|
+
"""Convert Python type to OpenAPI schema."""
|
276
|
+
if param_type is str or param_type == "str":
|
277
|
+
return {"type": "string"}
|
278
|
+
elif param_type is int or param_type == "int":
|
279
|
+
return {"type": "integer"}
|
280
|
+
elif param_type is float or param_type == "float":
|
281
|
+
return {"type": "number"}
|
282
|
+
elif param_type is bool or param_type == "bool":
|
283
|
+
return {"type": "boolean"}
|
284
|
+
elif param_type is list or (hasattr(param_type, "__origin__") and param_type.__origin__ is list):
|
285
|
+
return {"type": "array", "items": {}}
|
286
|
+
elif param_type is dict:
|
287
|
+
return {"type": "object"}
|
288
|
+
else:
|
289
|
+
return {"type": "string"}
|
290
|
+
|
291
|
+
|
292
|
+
__all__ = ["get_openapi_schema"]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/repository_interface.py.j2
RENAMED
File without changes
|
{vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/domain/service_interface.py.j2
RENAMED
File without changes
|
File without changes
|
File without changes
|
{vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/infrastructure/service_impl.py.j2
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/project/main_standard.py.j2
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/sqlalchemy/database_manager.py.j2
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{vega_framework-0.2.1 → vega_framework-0.2.2}/vega/cli/templates/web/routes_init_autodiscovery.py.j2
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|