fastapi-voyager 0.4.1__tar.gz → 0.4.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.
Files changed (42) hide show
  1. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/PKG-INFO +16 -10
  2. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/README.md +15 -9
  3. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/graph.py +3 -1
  4. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/type_helper.py +24 -2
  5. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/version.py +1 -1
  6. fastapi_voyager-0.4.2/src/fastapi_voyager/web/icon/android-chrome-192x192.png +0 -0
  7. fastapi_voyager-0.4.2/src/fastapi_voyager/web/icon/android-chrome-512x512.png +0 -0
  8. fastapi_voyager-0.4.2/src/fastapi_voyager/web/icon/apple-touch-icon.png +0 -0
  9. fastapi_voyager-0.4.2/src/fastapi_voyager/web/icon/favicon-16x16.png +0 -0
  10. fastapi_voyager-0.4.2/src/fastapi_voyager/web/icon/favicon-32x32.png +0 -0
  11. fastapi_voyager-0.4.2/src/fastapi_voyager/web/icon/favicon.ico +0 -0
  12. fastapi_voyager-0.4.2/src/fastapi_voyager/web/icon/site.webmanifest +1 -0
  13. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/index.html +8 -1
  14. fastapi_voyager-0.4.2/tests/demo_anno.py +65 -0
  15. fastapi_voyager-0.4.2/voyager.jpg +0 -0
  16. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/.gitignore +0 -0
  17. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/LICENSE +0 -0
  18. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/pyproject.toml +0 -0
  19. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/__init__.py +0 -0
  20. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/cli.py +0 -0
  21. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/filter.py +0 -0
  22. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/module.py +0 -0
  23. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/server.py +0 -0
  24. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/type.py +0 -0
  25. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/component/route-code-display.js +0 -0
  26. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/component/schema-code-display.js +0 -0
  27. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/component/schema-field-filter.js +0 -0
  28. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/graph-ui.js +0 -0
  29. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/graphviz.svg.css +0 -0
  30. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/graphviz.svg.js +0 -0
  31. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/quasar.min.css +0 -0
  32. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/quasar.min.js +0 -0
  33. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/src/fastapi_voyager/web/vue-main.js +0 -0
  34. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/__init__.py +0 -0
  35. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/demo.py +0 -0
  36. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/service/__init__.py +0 -0
  37. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/service/schema.py +0 -0
  38. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/test_analysis.py +0 -0
  39. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/test_import.py +0 -0
  40. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/test_module.py +0 -0
  41. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/tests/test_type_alias.py +0 -0
  42. {fastapi_voyager-0.4.1 → fastapi_voyager-0.4.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.4.1
3
+ Version: 0.4.2
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
  [![pypi](https://img.shields.io/pypi/v/fastapi-voyager.svg)](https://pypi.python.org/pypi/fastapi-voyager)
29
29
  ![Python Versions](https://img.shields.io/pypi/pyversions/fastapi-voyager)
30
30
 
31
- > This repo is still in early stage, currently it support pydantic v2 only, previous name: fastapi-router-viz
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
- pick tag, rotue (optional) and click `generate`.
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 nodes.
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="497" height="402" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/ac81711a-d9c2-4fb1-8b3a-0f4bd1f02572" />
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
- more in video:
98
+ <img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
92
99
 
93
- [![IMAGE ALT TEXT](http://img.youtube.com/vi/msYsB9Cc3CA/0.jpg)](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
  [![pypi](https://img.shields.io/pypi/v/fastapi-voyager.svg)](https://pypi.python.org/pypi/fastapi-voyager)
2
2
  ![Python Versions](https://img.shields.io/pypi/pyversions/fastapi-voyager)
3
3
 
4
- > This repo is still in early stage, currently it support pydantic v2 only, previous name: fastapi-router-viz
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
- pick tag, rotue (optional) and click `generate`.
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 nodes.
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="497" height="402" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/ac81711a-d9c2-4fb1-8b3a-0f4bd1f02572" />
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
- more in video:
71
+ <img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
65
72
 
66
- [![IMAGE ALT TEXT](http://img.youtube.com/vi/msYsB9Cc3CA/0.jpg)](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
@@ -111,6 +112,7 @@ class Analytics:
111
112
  # add response_models and create links from route -> response_model
112
113
  for schema in get_core_types(route.response_model):
113
114
  if schema and issubclass(schema, BaseModel):
115
+ update_forward_refs(schema)
114
116
  target_name = full_class_name(schema)
115
117
  self.links.append(Link(
116
118
  source=route_id,
@@ -1,7 +1,7 @@
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
7
 
@@ -229,4 +229,26 @@ def get_source(kls):
229
229
  source = inspect.getsource(kls)
230
230
  return source
231
231
  except Exception:
232
- return "failed to get source"
232
+ return "failed to get source"
233
+
234
+
235
+ def safe_issubclass(kls, classinfo):
236
+ try:
237
+ return issubclass(kls, classinfo)
238
+ except TypeError:
239
+ return False
240
+
241
+
242
+ def update_forward_refs(kls):
243
+ def update_pydantic_forward_refs(kls: Type[BaseModel]):
244
+ """
245
+ recursively update refs.
246
+ """
247
+ kls.model_rebuild()
248
+ values = kls.model_fields.values()
249
+ for field in values:
250
+ update_forward_refs(field.annotation)
251
+
252
+ for shelled_types in get_core_types(kls):
253
+ if safe_issubclass(shelled_types, BaseModel):
254
+ update_pydantic_forward_refs(shelled_types)
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.4.1"
2
+ __version__ = "0.4.2"
@@ -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 Router Viz</title>
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,65 @@
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 PageMember(serv.Member):
16
+ fullname: str = ''
17
+ def post_fullname(self):
18
+ return self.first_name + ' ' + self.last_name
19
+
20
+ class TaskA(Task):
21
+ task_type: str = 'A'
22
+
23
+ class TaskB(Task):
24
+ task_type: str = 'B'
25
+
26
+
27
+ type TaskUnion = TaskA | TaskB
28
+ class PageTask(Task):
29
+ owner: Optional[PageMember]
30
+
31
+
32
+ class PageOverall(BaseModel):
33
+ sprints: list[PageSprint]
34
+
35
+ class PageSprint(serv.Sprint):
36
+ stories: list[PageStory]
37
+ owner: Optional[PageMember] = None
38
+
39
+
40
+ @ensure_subset(Story)
41
+ class PageStory(BaseModel):
42
+ id: int
43
+ sprint_id: int
44
+ title: str = Field(exclude=True)
45
+
46
+ desc: str = ''
47
+ def post_desc(self):
48
+ return self.title + ' (processed)'
49
+
50
+ tasks: list[PageTask] = []
51
+ owner: Optional[PageMember] = None
52
+ union_tasks: list[TaskUnion] = []
53
+
54
+ @app.get("/page_overall", tags=['for-page'], response_model=PageOverall)
55
+ async def get_page_info():
56
+ page_overall = PageOverall(sprints=[]) # focus on schema only
57
+ return await Resolver().resolve(page_overall)
58
+
59
+
60
+ class PageStories(BaseModel):
61
+ stories: list[PageStory]
62
+
63
+ @app.get("/page_info/", tags=['for-page'], response_model=PageStories)
64
+ def get_page_stories():
65
+ return {} # no implementation
Binary file
File without changes
File without changes