fastapi-voyager 0.4.1__tar.gz → 0.4.3__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.
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/PKG-INFO +16 -10
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/README.md +15 -9
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/graph.py +3 -1
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/type_helper.py +42 -3
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/version.py +1 -1
- fastapi_voyager-0.4.3/src/fastapi_voyager/web/icon/android-chrome-192x192.png +0 -0
- fastapi_voyager-0.4.3/src/fastapi_voyager/web/icon/android-chrome-512x512.png +0 -0
- fastapi_voyager-0.4.3/src/fastapi_voyager/web/icon/apple-touch-icon.png +0 -0
- fastapi_voyager-0.4.3/src/fastapi_voyager/web/icon/favicon-16x16.png +0 -0
- fastapi_voyager-0.4.3/src/fastapi_voyager/web/icon/favicon-32x32.png +0 -0
- fastapi_voyager-0.4.3/src/fastapi_voyager/web/icon/favicon.ico +0 -0
- fastapi_voyager-0.4.3/src/fastapi_voyager/web/icon/site.webmanifest +1 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/index.html +8 -1
- fastapi_voyager-0.4.3/tests/demo_anno.py +72 -0
- fastapi_voyager-0.4.3/voyager.jpg +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/.gitignore +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/LICENSE +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/pyproject.toml +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/__init__.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/cli.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/filter.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/module.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/server.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/type.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/component/route-code-display.js +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/component/schema-code-display.js +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/component/schema-field-filter.js +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/graph-ui.js +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/graphviz.svg.css +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/graphviz.svg.js +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/quasar.min.css +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/quasar.min.js +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/src/fastapi_voyager/web/vue-main.js +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/__init__.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/demo.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/service/__init__.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/service/schema.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/test_analysis.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/test_import.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/test_module.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/tests/test_type_alias.py +0 -0
- {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.3}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-voyager
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Visualize FastAPI application's routing tree and dependencies
|
|
5
5
|
Project-URL: Homepage, https://github.com/allmonday/fastapi-voyager
|
|
6
6
|
Project-URL: Source, https://github.com/allmonday/fastapi-voyager
|
|
@@ -28,7 +28,9 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
[](https://pypi.python.org/pypi/fastapi-voyager)
|
|
29
29
|

|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
<p align="center"><img src="./voyager.jpg" alt="" /></p>
|
|
32
|
+
|
|
33
|
+
> This repo is still in early stage, currently it supports pydantic v2 only, previous name: fastapi-router-viz
|
|
32
34
|
|
|
33
35
|
Inspect your API interactively
|
|
34
36
|
|
|
@@ -69,28 +71,32 @@ voyager -m tests.demo
|
|
|
69
71
|
--module_color=tests.demo:tomato
|
|
70
72
|
```
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
### generate the graph
|
|
75
|
+
after initialization, pick tag, rotue (optional) and click `generate`.
|
|
73
76
|
|
|
74
77
|
<img width="1919" height="898" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/05e321d0-49f3-4af6-a7c7-f4c9c6b1dbfd" />
|
|
75
78
|
|
|
79
|
+
### highlight
|
|
76
80
|
click a node to highlight it's upperstream and downstream nodes. figure out the related models of one page, or homw many pages are related with one model.
|
|
77
81
|
|
|
78
82
|
<img width="1485" height="616" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/70c4095f-86c7-45da-a6f0-fd41ac645813" />
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
`shift` click a node to check related
|
|
82
|
-
|
|
83
|
-
pick a field to narrow the result.
|
|
84
|
+
### filter related nodes
|
|
85
|
+
`shift` click a node to check related node, pick a field to narrow the result.
|
|
84
86
|
|
|
85
87
|
<img width="1917" height="800" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/e770dc70-f293-49e1-bcd7-d8dffa15d9ea" />
|
|
86
88
|
|
|
89
|
+
### view source code
|
|
87
90
|
`alt` click a node to show source code or open file in vscode.
|
|
88
91
|
|
|
89
|
-
<img width="
|
|
92
|
+
<img width="1049" height="694" alt="image" src="https://github.com/user-attachments/assets/7839ac83-8d60-44ad-b1c9-9652a76339b1" />
|
|
93
|
+
|
|
94
|
+
<img width="1042" height="675" alt="image" src="https://github.com/user-attachments/assets/38ae705f-5982-4a02-9c3f-038b1d00bcf6" />
|
|
95
|
+
|
|
96
|
+
`alt` click a route to show source code or open file in vscode
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
<img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
|
|
92
99
|
|
|
93
|
-
[](https://www.youtube.com/watch?v=msYsB9Cc3CA "Unity Snake Game")
|
|
94
100
|
|
|
95
101
|
|
|
96
102
|
## Command Line Usage
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
[](https://pypi.python.org/pypi/fastapi-voyager)
|
|
2
2
|

|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
<p align="center"><img src="./voyager.jpg" alt="" /></p>
|
|
5
|
+
|
|
6
|
+
> This repo is still in early stage, currently it supports pydantic v2 only, previous name: fastapi-router-viz
|
|
5
7
|
|
|
6
8
|
Inspect your API interactively
|
|
7
9
|
|
|
@@ -42,28 +44,32 @@ voyager -m tests.demo
|
|
|
42
44
|
--module_color=tests.demo:tomato
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
### generate the graph
|
|
48
|
+
after initialization, pick tag, rotue (optional) and click `generate`.
|
|
46
49
|
|
|
47
50
|
<img width="1919" height="898" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/05e321d0-49f3-4af6-a7c7-f4c9c6b1dbfd" />
|
|
48
51
|
|
|
52
|
+
### highlight
|
|
49
53
|
click a node to highlight it's upperstream and downstream nodes. figure out the related models of one page, or homw many pages are related with one model.
|
|
50
54
|
|
|
51
55
|
<img width="1485" height="616" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/70c4095f-86c7-45da-a6f0-fd41ac645813" />
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
`shift` click a node to check related
|
|
55
|
-
|
|
56
|
-
pick a field to narrow the result.
|
|
57
|
+
### filter related nodes
|
|
58
|
+
`shift` click a node to check related node, pick a field to narrow the result.
|
|
57
59
|
|
|
58
60
|
<img width="1917" height="800" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/e770dc70-f293-49e1-bcd7-d8dffa15d9ea" />
|
|
59
61
|
|
|
62
|
+
### view source code
|
|
60
63
|
`alt` click a node to show source code or open file in vscode.
|
|
61
64
|
|
|
62
|
-
<img width="
|
|
65
|
+
<img width="1049" height="694" alt="image" src="https://github.com/user-attachments/assets/7839ac83-8d60-44ad-b1c9-9652a76339b1" />
|
|
66
|
+
|
|
67
|
+
<img width="1042" height="675" alt="image" src="https://github.com/user-attachments/assets/38ae705f-5982-4a02-9c3f-038b1d00bcf6" />
|
|
68
|
+
|
|
69
|
+
`alt` click a route to show source code or open file in vscode
|
|
63
70
|
|
|
64
|
-
|
|
71
|
+
<img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
|
|
65
72
|
|
|
66
|
-
[](https://www.youtube.com/watch?v=msYsB9Cc3CA "Unity Snake Game")
|
|
67
73
|
|
|
68
74
|
|
|
69
75
|
## Command Line Usage
|
|
@@ -8,7 +8,8 @@ from fastapi_voyager.type_helper import (
|
|
|
8
8
|
is_inheritance_of_pydantic_base,
|
|
9
9
|
get_pydantic_fields,
|
|
10
10
|
get_vscode_link,
|
|
11
|
-
get_source
|
|
11
|
+
get_source,
|
|
12
|
+
update_forward_refs
|
|
12
13
|
)
|
|
13
14
|
from pydantic import BaseModel
|
|
14
15
|
from fastapi_voyager.type import Route, SchemaNode, Link, Tag, ModuleNode
|
|
@@ -180,6 +181,7 @@ class Analytics:
|
|
|
180
181
|
3. recursively run walk_schema
|
|
181
182
|
"""
|
|
182
183
|
|
|
184
|
+
update_forward_refs(schema)
|
|
183
185
|
self.add_to_node_set(schema)
|
|
184
186
|
|
|
185
187
|
# handle schema inside ensure_subset(schema)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import os
|
|
3
3
|
from pydantic import BaseModel
|
|
4
|
-
from typing import get_origin, get_args, Union, Annotated, Any
|
|
4
|
+
from typing import get_origin, get_args, Union, Annotated, Any, Type
|
|
5
5
|
from fastapi_voyager.type import FieldInfo
|
|
6
6
|
from types import UnionType
|
|
7
|
+
import pydantic_resolve.constant as const
|
|
7
8
|
|
|
8
9
|
# Python <3.12 compatibility: TypeAliasType exists only from 3.12 (PEP 695)
|
|
9
10
|
try: # pragma: no cover - import guard
|
|
@@ -149,8 +150,9 @@ def get_type_name(anno):
|
|
|
149
150
|
|
|
150
151
|
return name_of(anno)
|
|
151
152
|
|
|
153
|
+
|
|
152
154
|
def is_inheritance_of_pydantic_base(cls):
|
|
153
|
-
|
|
155
|
+
return issubclass(cls, BaseModel) and cls is not BaseModel
|
|
154
156
|
|
|
155
157
|
|
|
156
158
|
def get_bases_fields(schemas: list[type[BaseModel]]) -> set[str]:
|
|
@@ -229,4 +231,41 @@ def get_source(kls):
|
|
|
229
231
|
source = inspect.getsource(kls)
|
|
230
232
|
return source
|
|
231
233
|
except Exception:
|
|
232
|
-
return "failed to get source"
|
|
234
|
+
return "failed to get source"
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def safe_issubclass(kls, classinfo):
|
|
238
|
+
try:
|
|
239
|
+
return issubclass(kls, classinfo)
|
|
240
|
+
except TypeError:
|
|
241
|
+
return False
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def update_forward_refs(kls):
|
|
245
|
+
def update_pydantic_forward_refs(kls2: Type[BaseModel]):
|
|
246
|
+
"""
|
|
247
|
+
recursively update refs.
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
kls2.model_rebuild()
|
|
251
|
+
setattr(kls2, const.PYDANTIC_FORWARD_REF_UPDATED, True)
|
|
252
|
+
|
|
253
|
+
values = kls2.model_fields.values()
|
|
254
|
+
for field in values:
|
|
255
|
+
update_forward_refs(field.annotation)
|
|
256
|
+
|
|
257
|
+
if safe_issubclass(kls, BaseModel):
|
|
258
|
+
kls.model_rebuild()
|
|
259
|
+
setattr(kls, const.PYDANTIC_FORWARD_REF_UPDATED, True)
|
|
260
|
+
|
|
261
|
+
for shelled_type in get_core_types(kls):
|
|
262
|
+
if getattr(shelled_type, const.PYDANTIC_FORWARD_REF_UPDATED, False):
|
|
263
|
+
continue
|
|
264
|
+
if safe_issubclass(shelled_type, BaseModel):
|
|
265
|
+
update_pydantic_forward_refs(shelled_type)
|
|
266
|
+
|
|
267
|
+
if __name__ == "__main__":
|
|
268
|
+
from tests.demo_anno import PageSprint, PageOverall
|
|
269
|
+
|
|
270
|
+
update_forward_refs(PageOverall)
|
|
271
|
+
update_forward_refs(PageSprint)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "0.4.
|
|
2
|
+
__version__ = "0.4.3"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
<html>
|
|
2
2
|
<head>
|
|
3
|
-
<title>FastAPI
|
|
3
|
+
<title>FastAPI Voyager</title>
|
|
4
|
+
<meta name="theme-color" content="#ffffff" />
|
|
4
5
|
<link rel="stylesheet" href="/static/graphviz.svg.css" />
|
|
5
6
|
<link rel="stylesheet" href="/static/quasar.min.css" />
|
|
7
|
+
<!-- App Icons / Favicons -->
|
|
8
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/static/icon/apple-touch-icon.png" />
|
|
9
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/static/icon/favicon-32x32.png" />
|
|
10
|
+
<link rel="icon" type="image/png" sizes="16x16" href="/static/icon/favicon-16x16.png" />
|
|
11
|
+
<link rel="icon" href="/static/icon/favicon.ico" sizes="any" />
|
|
12
|
+
<link rel="manifest" href="/static/icon/site.webmanifest" />
|
|
6
13
|
<link
|
|
7
14
|
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
|
|
8
15
|
rel="stylesheet"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from pydantic_resolve import ensure_subset, Resolver
|
|
6
|
+
from tests.service.schema import Story, Task
|
|
7
|
+
import tests.service.schema as serv
|
|
8
|
+
|
|
9
|
+
app = FastAPI(title="Demo API", description="A demo FastAPI application for router visualization")
|
|
10
|
+
|
|
11
|
+
@app.get("/sprints", tags=['for-restapi'], response_model=list[serv.Sprint])
|
|
12
|
+
def get_sprint():
|
|
13
|
+
return []
|
|
14
|
+
|
|
15
|
+
class Tree(BaseModel):
|
|
16
|
+
id: int
|
|
17
|
+
name: str
|
|
18
|
+
children: list[Tree] = []
|
|
19
|
+
|
|
20
|
+
class PageMember(serv.Member):
|
|
21
|
+
fullname: str = ''
|
|
22
|
+
def post_fullname(self):
|
|
23
|
+
return self.first_name + ' ' + self.last_name
|
|
24
|
+
|
|
25
|
+
class TaskA(Task):
|
|
26
|
+
task_type: str = 'A'
|
|
27
|
+
|
|
28
|
+
class TaskB(Task):
|
|
29
|
+
task_type: str = 'B'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
type TaskUnion = TaskA | TaskB
|
|
33
|
+
class PageTask(Task):
|
|
34
|
+
owner: Optional[PageMember]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class PageOverall(BaseModel):
|
|
38
|
+
sprints: list[PageSprint]
|
|
39
|
+
|
|
40
|
+
class PageSprint(serv.Sprint):
|
|
41
|
+
stories: list[PageStory]
|
|
42
|
+
owner: Optional[PageMember] = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@ensure_subset(Story)
|
|
46
|
+
class PageStory(BaseModel):
|
|
47
|
+
id: int
|
|
48
|
+
sprint_id: int
|
|
49
|
+
title: str = Field(exclude=True)
|
|
50
|
+
|
|
51
|
+
desc: str = ''
|
|
52
|
+
def post_desc(self):
|
|
53
|
+
return self.title + ' (processed)'
|
|
54
|
+
|
|
55
|
+
tasks: list[PageTask] = []
|
|
56
|
+
owner: Optional[PageMember] = None
|
|
57
|
+
union_tasks: list[TaskUnion] = []
|
|
58
|
+
|
|
59
|
+
tree: Optional[Tree] = None
|
|
60
|
+
|
|
61
|
+
@app.get("/page_overall", tags=['for-page'], response_model=PageOverall)
|
|
62
|
+
async def get_page_info():
|
|
63
|
+
page_overall = PageOverall(sprints=[]) # focus on schema only
|
|
64
|
+
return await Resolver().resolve(page_overall)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PageStories(BaseModel):
|
|
68
|
+
stories: list[PageStory]
|
|
69
|
+
|
|
70
|
+
@app.get("/page_info/", tags=['for-page'], response_model=PageStories)
|
|
71
|
+
def get_page_stories():
|
|
72
|
+
return {} # no implementation
|
|
Binary file
|
|
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
|