fastapi-voyager 0.15.6__py3-none-any.whl → 0.16.0a1__py3-none-any.whl
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.
- fastapi_voyager/__init__.py +2 -2
- fastapi_voyager/adapters/__init__.py +16 -0
- fastapi_voyager/adapters/base.py +44 -0
- fastapi_voyager/adapters/common.py +260 -0
- fastapi_voyager/adapters/django_ninja_adapter.py +299 -0
- fastapi_voyager/adapters/fastapi_adapter.py +165 -0
- fastapi_voyager/adapters/litestar_adapter.py +188 -0
- fastapi_voyager/er_diagram.py +15 -14
- fastapi_voyager/introspectors/__init__.py +34 -0
- fastapi_voyager/introspectors/base.py +81 -0
- fastapi_voyager/introspectors/detector.py +123 -0
- fastapi_voyager/introspectors/django_ninja.py +114 -0
- fastapi_voyager/introspectors/fastapi.py +83 -0
- fastapi_voyager/introspectors/litestar.py +166 -0
- fastapi_voyager/pydantic_resolve_util.py +4 -2
- fastapi_voyager/render.py +2 -2
- fastapi_voyager/render_style.py +0 -1
- fastapi_voyager/server.py +174 -295
- fastapi_voyager/type_helper.py +2 -2
- fastapi_voyager/version.py +1 -1
- fastapi_voyager/voyager.py +75 -47
- fastapi_voyager/web/index.html +11 -14
- fastapi_voyager/web/store.js +2 -0
- fastapi_voyager/web/vue-main.js +4 -0
- {fastapi_voyager-0.15.6.dist-info → fastapi_voyager-0.16.0a1.dist-info}/METADATA +133 -7
- {fastapi_voyager-0.15.6.dist-info → fastapi_voyager-0.16.0a1.dist-info}/RECORD +29 -17
- {fastapi_voyager-0.15.6.dist-info → fastapi_voyager-0.16.0a1.dist-info}/WHEEL +0 -0
- {fastapi_voyager-0.15.6.dist-info → fastapi_voyager-0.16.0a1.dist-info}/entry_points.txt +0 -0
- {fastapi_voyager-0.15.6.dist-info → fastapi_voyager-0.16.0a1.dist-info}/licenses/LICENSE +0 -0
fastapi_voyager/server.py
CHANGED
|
@@ -1,302 +1,181 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from typing import Literal
|
|
3
|
-
|
|
4
|
-
from fastapi import APIRouter, FastAPI
|
|
5
|
-
from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
|
|
6
|
-
from fastapi.staticfiles import StaticFiles
|
|
7
|
-
from pydantic import BaseModel
|
|
8
|
-
from starlette.middleware.gzip import GZipMiddleware
|
|
9
|
-
|
|
10
|
-
from fastapi_voyager.render import Renderer
|
|
11
|
-
from fastapi_voyager.type import CoreData, SchemaNode, Tag
|
|
12
|
-
from fastapi_voyager.type_helper import get_source, get_vscode_link
|
|
13
|
-
from fastapi_voyager.version import __version__
|
|
14
|
-
from fastapi_voyager.voyager import Voyager
|
|
15
|
-
from pydantic_resolve import ErDiagram
|
|
16
|
-
from fastapi_voyager.er_diagram import VoyagerErDiagram
|
|
17
|
-
|
|
18
|
-
WEB_DIR = Path(__file__).parent / "web"
|
|
19
|
-
WEB_DIR.mkdir(exist_ok=True)
|
|
20
|
-
|
|
21
|
-
GA_PLACEHOLDER = "<!-- GA_SNIPPET -->"
|
|
22
|
-
VERSION_PLACEHOLDER = "<!-- VERSION_PLACEHOLDER -->"
|
|
23
|
-
|
|
24
|
-
def _build_ga_snippet(ga_id: str | None) -> str:
|
|
25
|
-
if not ga_id:
|
|
26
|
-
return ""
|
|
27
|
-
|
|
28
|
-
return f""" <script async src="https://www.googletagmanager.com/gtag/js?id={ga_id}"></script>
|
|
29
|
-
<script>
|
|
30
|
-
window.dataLayer = window.dataLayer || [];
|
|
31
|
-
function gtag(){{dataLayer.push(arguments);}}
|
|
32
|
-
gtag('js', new Date());
|
|
33
|
-
|
|
34
|
-
gtag('config', '{ga_id}');
|
|
35
|
-
</script>
|
|
36
1
|
"""
|
|
2
|
+
FastAPI-voyager server module with framework adapter support.
|
|
37
3
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class OptionParam(BaseModel):
|
|
43
|
-
tags: list[Tag]
|
|
44
|
-
schemas: list[SchemaNode]
|
|
45
|
-
dot: str
|
|
46
|
-
enable_brief_mode: bool
|
|
47
|
-
version: str
|
|
48
|
-
initial_page_policy: INITIAL_PAGE_POLICY
|
|
49
|
-
swagger_url: str | None = None
|
|
50
|
-
has_er_diagram: bool = False
|
|
51
|
-
enable_pydantic_resolve_meta: bool = False
|
|
52
|
-
|
|
53
|
-
class Payload(BaseModel):
|
|
54
|
-
tags: list[str] | None = None
|
|
55
|
-
schema_name: str | None = None
|
|
56
|
-
schema_field: str | None = None
|
|
57
|
-
route_name: str | None = None
|
|
58
|
-
show_fields: str = 'object'
|
|
59
|
-
brief: bool = False
|
|
60
|
-
hide_primitive_route: bool = False
|
|
61
|
-
show_module: bool = True
|
|
62
|
-
show_pydantic_resolve_meta: bool = False
|
|
63
|
-
|
|
64
|
-
# ---------- search ----------
|
|
65
|
-
class SearchResultOptionParam(BaseModel):
|
|
66
|
-
tags: list[Tag]
|
|
4
|
+
This module provides the main `create_voyager` function that automatically
|
|
5
|
+
detects the framework type and returns an appropriately configured voyager UI.
|
|
6
|
+
"""
|
|
7
|
+
from typing import Any, Literal
|
|
67
8
|
|
|
68
|
-
|
|
69
|
-
schema_name: str | None = None
|
|
70
|
-
schema_field: str | None = None
|
|
71
|
-
show_fields: str = 'object'
|
|
72
|
-
brief: bool = False
|
|
73
|
-
hide_primitive_route: bool = False
|
|
74
|
-
show_module: bool = True
|
|
75
|
-
show_pydantic_resolve_meta: bool = False
|
|
9
|
+
from pydantic_resolve import ErDiagram
|
|
76
10
|
|
|
11
|
+
from fastapi_voyager.adapters import DjangoNinjaAdapter, FastAPIAdapter, LitestarAdapter
|
|
12
|
+
from fastapi_voyager.introspectors import FrameworkType, detect_framework
|
|
13
|
+
|
|
14
|
+
INITIAL_PAGE_POLICY = Literal["first", "full", "empty"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _get_adapter(
|
|
18
|
+
target_app: Any,
|
|
19
|
+
module_color: dict[str, str] | None = None,
|
|
20
|
+
gzip_minimum_size: int | None = 500,
|
|
21
|
+
module_prefix: str | None = None,
|
|
22
|
+
swagger_url: str | None = None,
|
|
23
|
+
online_repo_url: str | None = None,
|
|
24
|
+
initial_page_policy: INITIAL_PAGE_POLICY = "first",
|
|
25
|
+
ga_id: str | None = None,
|
|
26
|
+
er_diagram: ErDiagram | None = None,
|
|
27
|
+
enable_pydantic_resolve_meta: bool = False,
|
|
28
|
+
) -> Any:
|
|
29
|
+
"""
|
|
30
|
+
Get the appropriate adapter for the given target app.
|
|
31
|
+
|
|
32
|
+
Automatically detects the framework type and returns the matching adapter.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
target_app: The web application instance to introspect
|
|
36
|
+
module_color: Optional color mapping for modules
|
|
37
|
+
gzip_minimum_size: Minimum size for gzip compression
|
|
38
|
+
module_prefix: Optional module prefix for filtering
|
|
39
|
+
swagger_url: Optional custom URL to Swagger documentation
|
|
40
|
+
online_repo_url: Optional online repository URL for source links
|
|
41
|
+
initial_page_policy: Initial page display policy
|
|
42
|
+
ga_id: Optional Google Analytics ID
|
|
43
|
+
er_diagram: Optional ER diagram from pydantic-resolve
|
|
44
|
+
enable_pydantic_resolve_meta: Enable pydantic-resolve metadata display
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
An adapter instance for the detected framework
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
TypeError: If the app type is not supported
|
|
51
|
+
"""
|
|
52
|
+
# Use centralized framework detection from introspectors
|
|
53
|
+
framework = detect_framework(target_app)
|
|
54
|
+
|
|
55
|
+
if framework == FrameworkType.FASTAPI:
|
|
56
|
+
return FastAPIAdapter(
|
|
57
|
+
target_app=target_app,
|
|
58
|
+
module_color=module_color,
|
|
59
|
+
gzip_minimum_size=gzip_minimum_size,
|
|
60
|
+
module_prefix=module_prefix,
|
|
61
|
+
swagger_url=swagger_url,
|
|
62
|
+
online_repo_url=online_repo_url,
|
|
63
|
+
initial_page_policy=initial_page_policy,
|
|
64
|
+
ga_id=ga_id,
|
|
65
|
+
er_diagram=er_diagram,
|
|
66
|
+
enable_pydantic_resolve_meta=enable_pydantic_resolve_meta,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
elif framework == FrameworkType.LITESTAR:
|
|
70
|
+
return LitestarAdapter(
|
|
71
|
+
target_app=target_app,
|
|
72
|
+
module_color=module_color,
|
|
73
|
+
gzip_minimum_size=gzip_minimum_size,
|
|
74
|
+
module_prefix=module_prefix,
|
|
75
|
+
swagger_url=swagger_url,
|
|
76
|
+
online_repo_url=online_repo_url,
|
|
77
|
+
initial_page_policy=initial_page_policy,
|
|
78
|
+
ga_id=ga_id,
|
|
79
|
+
er_diagram=er_diagram,
|
|
80
|
+
enable_pydantic_resolve_meta=enable_pydantic_resolve_meta,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
elif framework == FrameworkType.DJANGO_NINJA:
|
|
84
|
+
return DjangoNinjaAdapter(
|
|
85
|
+
target_app=target_app,
|
|
86
|
+
module_color=module_color,
|
|
87
|
+
gzip_minimum_size=gzip_minimum_size, # Note: ignored for Django
|
|
88
|
+
module_prefix=module_prefix,
|
|
89
|
+
swagger_url=swagger_url,
|
|
90
|
+
online_repo_url=online_repo_url,
|
|
91
|
+
initial_page_policy=initial_page_policy,
|
|
92
|
+
ga_id=ga_id,
|
|
93
|
+
er_diagram=er_diagram,
|
|
94
|
+
enable_pydantic_resolve_meta=enable_pydantic_resolve_meta,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# If we get here, the app type is not supported
|
|
98
|
+
raise TypeError(
|
|
99
|
+
f"Unsupported app type: {type(target_app).__name__}. "
|
|
100
|
+
f"Supported types: FastAPI, Django Ninja API, Litestar. "
|
|
101
|
+
f"If you're using a different framework, please implement a VoyagerAdapter for that framework. "
|
|
102
|
+
f"See fastapi_voyager/adapters/ for examples."
|
|
103
|
+
)
|
|
77
104
|
|
|
78
|
-
# ---------- er diagram ----------
|
|
79
|
-
class ErDiagramPayload(BaseModel):
|
|
80
|
-
show_fields: str = 'object'
|
|
81
|
-
show_module: bool = True
|
|
82
105
|
|
|
83
106
|
def create_voyager(
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
show_fields=payload.show_fields,
|
|
160
|
-
module_color=module_color,
|
|
161
|
-
route_name=payload.route_name,
|
|
162
|
-
hide_primitive_route=payload.hide_primitive_route,
|
|
163
|
-
show_module=payload.show_module,
|
|
164
|
-
show_pydantic_resolve_meta=payload.show_pydantic_resolve_meta,
|
|
165
|
-
)
|
|
166
|
-
voyager.analysis(target_app)
|
|
167
|
-
if payload.brief:
|
|
168
|
-
if payload.tags:
|
|
169
|
-
return voyager.render_tag_level_brief_dot(module_prefix=module_prefix)
|
|
170
|
-
else:
|
|
171
|
-
return voyager.render_overall_brief_dot(module_prefix=module_prefix)
|
|
172
|
-
else:
|
|
173
|
-
return voyager.render_dot()
|
|
174
|
-
|
|
175
|
-
@router.post("/dot-core-data", response_model=CoreData)
|
|
176
|
-
def get_filtered_dot_core_data(payload: Payload) -> str:
|
|
177
|
-
voyager = Voyager(
|
|
178
|
-
include_tags=payload.tags,
|
|
179
|
-
schema=payload.schema_name,
|
|
180
|
-
schema_field=payload.schema_field,
|
|
181
|
-
show_fields=payload.show_fields,
|
|
182
|
-
module_color=module_color,
|
|
183
|
-
route_name=payload.route_name,
|
|
184
|
-
)
|
|
185
|
-
voyager.analysis(target_app)
|
|
186
|
-
return voyager.dump_core_data()
|
|
187
|
-
|
|
188
|
-
@router.post('/dot-render-core-data', response_class=PlainTextResponse)
|
|
189
|
-
def render_dot_from_core_data(core_data: CoreData) -> str:
|
|
190
|
-
renderer = Renderer(
|
|
191
|
-
show_fields=core_data.show_fields,
|
|
192
|
-
module_color=core_data.module_color,
|
|
193
|
-
schema=core_data.schema)
|
|
194
|
-
return renderer.render_dot(core_data.tags, core_data.routes, core_data.nodes, core_data.links)
|
|
195
|
-
|
|
196
|
-
@router.get("/", response_class=HTMLResponse)
|
|
197
|
-
def index():
|
|
198
|
-
index_file = WEB_DIR / "index.html"
|
|
199
|
-
if index_file.exists():
|
|
200
|
-
content = index_file.read_text(encoding="utf-8")
|
|
201
|
-
content = content.replace(GA_PLACEHOLDER, _build_ga_snippet(ga_id))
|
|
202
|
-
content = content.replace(VERSION_PLACEHOLDER, f"?v={__version__}")
|
|
203
|
-
return content
|
|
204
|
-
# fallback simple page if index.html missing
|
|
205
|
-
return """
|
|
206
|
-
<!doctype html>
|
|
207
|
-
<html>
|
|
208
|
-
<head><meta charset=\"utf-8\"><title>Graphviz Preview</title></head>
|
|
209
|
-
<body>
|
|
210
|
-
<p>index.html not found. Create one under src/fastapi_voyager/web/index.html</p>
|
|
211
|
-
</body>
|
|
212
|
-
</html>
|
|
213
|
-
"""
|
|
214
|
-
|
|
215
|
-
class SourcePayload(BaseModel):
|
|
216
|
-
schema_name: str
|
|
217
|
-
|
|
218
|
-
@router.post("/source")
|
|
219
|
-
def get_object_by_module_name(payload: SourcePayload):
|
|
220
|
-
"""
|
|
221
|
-
input: __module__ + __name__, eg: tests.demo.PageStories
|
|
222
|
-
output: source code of the object
|
|
223
|
-
"""
|
|
224
|
-
try:
|
|
225
|
-
components = payload.schema_name.split('.')
|
|
226
|
-
if len(components) < 2:
|
|
227
|
-
return JSONResponse(
|
|
228
|
-
status_code=400,
|
|
229
|
-
content={"error": "Invalid schema name format. Expected format: module.ClassName"}
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
module_name = '.'.join(components[:-1])
|
|
233
|
-
class_name = components[-1]
|
|
234
|
-
|
|
235
|
-
mod = __import__(module_name, fromlist=[class_name])
|
|
236
|
-
obj = getattr(mod, class_name)
|
|
237
|
-
source_code = get_source(obj)
|
|
238
|
-
|
|
239
|
-
return JSONResponse(content={"source_code": source_code})
|
|
240
|
-
except ImportError as e:
|
|
241
|
-
return JSONResponse(
|
|
242
|
-
status_code=404,
|
|
243
|
-
content={"error": f"Module not found: {e}"}
|
|
244
|
-
)
|
|
245
|
-
except AttributeError as e:
|
|
246
|
-
return JSONResponse(
|
|
247
|
-
status_code=404,
|
|
248
|
-
content={"error": f"Class not found: {e}"}
|
|
249
|
-
)
|
|
250
|
-
except Exception as e:
|
|
251
|
-
return JSONResponse(
|
|
252
|
-
status_code=500,
|
|
253
|
-
content={"error": f"Internal error: {str(e)}"}
|
|
254
|
-
)
|
|
255
|
-
|
|
256
|
-
@router.post("/vscode-link")
|
|
257
|
-
def get_vscode_link_by_module_name(payload: SourcePayload):
|
|
258
|
-
"""
|
|
259
|
-
input: __module__ + __name__, eg: tests.demo.PageStories
|
|
260
|
-
output: source path of the object
|
|
261
|
-
"""
|
|
262
|
-
try:
|
|
263
|
-
components = payload.schema_name.split('.')
|
|
264
|
-
if len(components) < 2:
|
|
265
|
-
return JSONResponse(
|
|
266
|
-
status_code=400,
|
|
267
|
-
content={"error": "Invalid schema name format. Expected format: module.ClassName"}
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
module_name = '.'.join(components[:-1])
|
|
271
|
-
class_name = components[-1]
|
|
272
|
-
|
|
273
|
-
mod = __import__(module_name, fromlist=[class_name])
|
|
274
|
-
obj = getattr(mod, class_name)
|
|
275
|
-
link = get_vscode_link(obj, online_repo_url=online_repo_url)
|
|
276
|
-
|
|
277
|
-
return JSONResponse(content={"link": link})
|
|
278
|
-
except ImportError as e:
|
|
279
|
-
return JSONResponse(
|
|
280
|
-
status_code=404,
|
|
281
|
-
content={"error": f"Module not found: {e}"}
|
|
282
|
-
)
|
|
283
|
-
except AttributeError as e:
|
|
284
|
-
return JSONResponse(
|
|
285
|
-
status_code=404,
|
|
286
|
-
content={"error": f"Class not found: {e}"}
|
|
287
|
-
)
|
|
288
|
-
except Exception as e:
|
|
289
|
-
return JSONResponse(
|
|
290
|
-
status_code=500,
|
|
291
|
-
content={"error": f"Internal error: {str(e)}"}
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
app = FastAPI(title="fastapi-voyager demo server")
|
|
295
|
-
if gzip_minimum_size is not None and gzip_minimum_size >= 0:
|
|
296
|
-
app.add_middleware(GZipMiddleware, minimum_size=gzip_minimum_size)
|
|
297
|
-
|
|
298
|
-
app.mount("/fastapi-voyager-static", StaticFiles(directory=str(WEB_DIR)), name="static")
|
|
299
|
-
app.include_router(router)
|
|
300
|
-
|
|
301
|
-
return app
|
|
302
|
-
|
|
107
|
+
target_app: Any,
|
|
108
|
+
module_color: dict[str, str] | None = None,
|
|
109
|
+
gzip_minimum_size: int | None = 500,
|
|
110
|
+
module_prefix: str | None = None,
|
|
111
|
+
swagger_url: str | None = None,
|
|
112
|
+
online_repo_url: str | None = None,
|
|
113
|
+
initial_page_policy: INITIAL_PAGE_POLICY = "first",
|
|
114
|
+
ga_id: str | None = None,
|
|
115
|
+
er_diagram: ErDiagram | None = None,
|
|
116
|
+
enable_pydantic_resolve_meta: bool = False,
|
|
117
|
+
) -> Any:
|
|
118
|
+
"""
|
|
119
|
+
Create a voyager UI application for the given target app.
|
|
120
|
+
|
|
121
|
+
This function automatically detects the framework type (FastAPI, Django Ninja, or Litestar)
|
|
122
|
+
and returns an appropriately configured voyager UI application.
|
|
123
|
+
|
|
124
|
+
For FastAPI: Returns a FastAPI app that can be mounted
|
|
125
|
+
For Django Ninja: Returns an ASGI application
|
|
126
|
+
For Litestar: Returns a Litestar app
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
target_app: The web application to visualize
|
|
130
|
+
module_color: Optional color mapping for modules (e.g., {"myapp": "blue"})
|
|
131
|
+
gzip_minimum_size: Minimum response size for gzip compression (set to <0 to disable)
|
|
132
|
+
module_prefix: Optional module prefix for filtering/organization
|
|
133
|
+
swagger_url: Optional custom URL to Swagger/OpenAPI documentation
|
|
134
|
+
online_repo_url: Optional base URL for online repository source links
|
|
135
|
+
initial_page_policy: Initial page display policy ('first', 'full', or 'empty')
|
|
136
|
+
ga_id: Optional Google Analytics tracking ID
|
|
137
|
+
er_diagram: Optional ER diagram from pydantic-resolve
|
|
138
|
+
enable_pydantic_resolve_meta: Enable display of pydantic-resolve metadata
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
A framework-specific application object that provides the voyager UI
|
|
142
|
+
|
|
143
|
+
Example:
|
|
144
|
+
# FastAPI
|
|
145
|
+
from fastapi import FastAPI
|
|
146
|
+
from fastapi_voyager import create_voyager
|
|
147
|
+
|
|
148
|
+
app = FastAPI()
|
|
149
|
+
voyager_app = create_voyager(app)
|
|
150
|
+
app.mount("/voyager", voyager_app)
|
|
151
|
+
|
|
152
|
+
# Django Ninja
|
|
153
|
+
from ninja import NinjaAPI
|
|
154
|
+
from fastapi_voyager import create_voyager
|
|
155
|
+
|
|
156
|
+
api = NinjaAPI()
|
|
157
|
+
voyager_asgi_app = create_voyager(api)
|
|
158
|
+
# See django_ninja tests for integration examples
|
|
159
|
+
|
|
160
|
+
# Litestar
|
|
161
|
+
from litestar import Litestar
|
|
162
|
+
from fastapi_voyager import create_voyager
|
|
163
|
+
|
|
164
|
+
app = Litestar()
|
|
165
|
+
voyager_app = create_voyager(app)
|
|
166
|
+
# Mount or integrate as needed
|
|
167
|
+
"""
|
|
168
|
+
adapter = _get_adapter(
|
|
169
|
+
target_app=target_app,
|
|
170
|
+
module_color=module_color,
|
|
171
|
+
gzip_minimum_size=gzip_minimum_size,
|
|
172
|
+
module_prefix=module_prefix,
|
|
173
|
+
swagger_url=swagger_url,
|
|
174
|
+
online_repo_url=online_repo_url,
|
|
175
|
+
initial_page_policy=initial_page_policy,
|
|
176
|
+
ga_id=ga_id,
|
|
177
|
+
er_diagram=er_diagram,
|
|
178
|
+
enable_pydantic_resolve_meta=enable_pydantic_resolve_meta,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
return adapter.create_app()
|
fastapi_voyager/type_helper.py
CHANGED
|
@@ -2,13 +2,13 @@ import inspect
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
from types import UnionType
|
|
5
|
-
from typing import Annotated, Any, Generic, Union, get_args, get_origin
|
|
5
|
+
from typing import Annotated, Any, ForwardRef, Generic, Union, get_args, get_origin
|
|
6
6
|
|
|
7
7
|
import pydantic_resolve.constant as const
|
|
8
8
|
from pydantic import BaseModel
|
|
9
9
|
|
|
10
|
-
from fastapi_voyager.type import FieldInfo
|
|
11
10
|
from fastapi_voyager.pydantic_resolve_util import analysis_pydantic_resolve_fields
|
|
11
|
+
from fastapi_voyager.type import FieldInfo
|
|
12
12
|
|
|
13
13
|
logger = logging.getLogger(__name__)
|
|
14
14
|
|
fastapi_voyager/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.16.0alpha-1"
|