fastapi-voyager 0.7.6__tar.gz → 0.8.1__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 (49) hide show
  1. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/PKG-INFO +10 -2
  2. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/README.md +9 -1
  3. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/render.py +1 -1
  4. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/server.py +3 -1
  5. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/type.py +2 -0
  6. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/type_helper.py +6 -0
  7. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/version.py +1 -1
  8. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/voyager.py +22 -10
  9. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/index.html +7 -6
  10. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/vue-main.js +16 -1
  11. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/demo.py +5 -1
  12. fastapi_voyager-0.8.1/tests/programatic.py +4 -0
  13. fastapi_voyager-0.7.6/tests/programatic.py +0 -8
  14. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/.gitignore +0 -0
  15. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/.python-version +0 -0
  16. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/LICENSE +0 -0
  17. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/pyproject.toml +0 -0
  18. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/__init__.py +0 -0
  19. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/cli.py +0 -0
  20. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/filter.py +0 -0
  21. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/module.py +0 -0
  22. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/component/render-graph.js +0 -0
  23. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/component/route-code-display.js +0 -0
  24. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/component/schema-code-display.js +0 -0
  25. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/component/schema-field-filter.js +0 -0
  26. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/graph-ui.js +0 -0
  27. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/graphviz.svg.css +0 -0
  28. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/graphviz.svg.js +0 -0
  29. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/icon/android-chrome-192x192.png +0 -0
  30. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/icon/android-chrome-512x512.png +0 -0
  31. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/icon/apple-touch-icon.png +0 -0
  32. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/icon/favicon-16x16.png +0 -0
  33. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/icon/favicon-32x32.png +0 -0
  34. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/icon/favicon.ico +0 -0
  35. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/icon/site.webmanifest +0 -0
  36. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/quasar.min.css +0 -0
  37. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/src/fastapi_voyager/web/quasar.min.js +0 -0
  38. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/__init__.py +0 -0
  39. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/demo_anno.py +0 -0
  40. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/service/__init__.py +0 -0
  41. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/service/schema.py +0 -0
  42. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/test_analysis.py +0 -0
  43. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/test_filter.py +0 -0
  44. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/test_generic.py +0 -0
  45. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/test_import.py +0 -0
  46. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/test_module.py +0 -0
  47. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/tests/test_type_helper.py +0 -0
  48. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/uv.lock +0 -0
  49. {fastapi_voyager-0.7.6 → fastapi_voyager-0.8.1}/voyager.jpg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.7.6
3
+ Version: 0.8.1
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
@@ -108,7 +108,10 @@ from fastapi import FastAPI
108
108
  from fastapi_voyager.server import create_app_with_fastapi
109
109
  from tests.demo import app
110
110
 
111
- app.mount('/voyager', create_app_with_fastapi(app))
111
+ app.mount('/voyager', create_app_with_fastapi(
112
+ app,
113
+ module_color={"tests.service": "red"},
114
+ module_prefix="tests.service"))
112
115
  ```
113
116
 
114
117
  more about [sub application](https://fastapi.tiangolo.com/advanced/sub-applications/?h=sub)
@@ -198,6 +201,8 @@ features:
198
201
  - [x] export voyager core data into json (for better debugging)
199
202
  - [x] add api to rebuild core data from json, and render it
200
203
  - [x] fix Generic case `test_generic.py`
204
+ - [ ] show tips for routes not return pydantic type.
205
+ - [ ] add http method for route
201
206
 
202
207
  bugs & non feature:
203
208
  - [x] fix duplicated link from class and parent class, it also break clicking highlight
@@ -220,6 +225,9 @@ TODO: ...
220
225
 
221
226
  ## Changelog
222
227
 
228
+ - 0.8:
229
+ - 0.8.1
230
+ - add feature: hide primitive routes
223
231
  - 0.7:
224
232
  - 0.7.5
225
233
  - fix show all display issue
@@ -81,7 +81,10 @@ from fastapi import FastAPI
81
81
  from fastapi_voyager.server import create_app_with_fastapi
82
82
  from tests.demo import app
83
83
 
84
- app.mount('/voyager', create_app_with_fastapi(app))
84
+ app.mount('/voyager', create_app_with_fastapi(
85
+ app,
86
+ module_color={"tests.service": "red"},
87
+ module_prefix="tests.service"))
85
88
  ```
86
89
 
87
90
  more about [sub application](https://fastapi.tiangolo.com/advanced/sub-applications/?h=sub)
@@ -171,6 +174,8 @@ features:
171
174
  - [x] export voyager core data into json (for better debugging)
172
175
  - [x] add api to rebuild core data from json, and render it
173
176
  - [x] fix Generic case `test_generic.py`
177
+ - [ ] show tips for routes not return pydantic type.
178
+ - [ ] add http method for route
174
179
 
175
180
  bugs & non feature:
176
181
  - [x] fix duplicated link from class and parent class, it also break clicking highlight
@@ -193,6 +198,9 @@ TODO: ...
193
198
 
194
199
  ## Changelog
195
200
 
201
+ - 0.8:
202
+ - 0.8.1
203
+ - add feature: hide primitive routes
196
204
  - 0.7:
197
205
  - 0.7.5
198
206
  - fix show all display issue
@@ -104,7 +104,7 @@ class Renderer:
104
104
  inner_nodes = [
105
105
  f'''
106
106
  "{r.id}" [
107
- label = " {r.name} "
107
+ label = " {r.name}: {r.response_schema} "
108
108
  margin="0.5,0.1"
109
109
  shape = "record"
110
110
  ];''' for r in mod.routes
@@ -32,7 +32,8 @@ class Payload(BaseModel):
32
32
  route_name: Optional[str] = None
33
33
  show_fields: str = 'object'
34
34
  show_meta: bool = False
35
- brief: bool = False
35
+ brief: bool = False,
36
+ hide_primitive_route: bool = False,
36
37
 
37
38
  def create_route(
38
39
  target_app: FastAPI,
@@ -73,6 +74,7 @@ def create_route(
73
74
  module_color=module_color,
74
75
  route_name=payload.route_name,
75
76
  load_meta=False,
77
+ hide_primitive_route=payload.hide_primitive_route,
76
78
  )
77
79
  voyager.analysis(target_app)
78
80
  if payload.brief:
@@ -24,6 +24,8 @@ class Route(NodeBase):
24
24
  module: str
25
25
  source_code: str = ''
26
26
  vscode_link: str = '' # optional vscode deep link
27
+ response_schema: str = ''
28
+ is_primitive: bool = True
27
29
 
28
30
  @dataclass
29
31
  class ModuleRoute:
@@ -276,6 +276,12 @@ def is_generic_container(cls):
276
276
  return (hasattr(cls, '__bases__') and Generic in cls.__bases__ and (hasattr(cls, '__parameters__') and bool(cls.__parameters__)))
277
277
  except (TypeError, AttributeError):
278
278
  return False
279
+
280
+ def is_non_pydantic_type(tp):
281
+ for schema in get_core_types(tp):
282
+ if schema and issubclass(schema, BaseModel):
283
+ return False
284
+ return True
279
285
 
280
286
  if __name__ == "__main__":
281
287
  from tests.demo_anno import PageSprint, PageOverall
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.7.6"
2
+ __version__ = "0.8.1"
@@ -8,7 +8,9 @@ from fastapi_voyager.type_helper import (
8
8
  get_pydantic_fields,
9
9
  get_vscode_link,
10
10
  get_source,
11
- update_forward_refs
11
+ get_type_name,
12
+ update_forward_refs,
13
+ is_non_pydantic_type
12
14
  )
13
15
  from pydantic import BaseModel
14
16
  from fastapi_voyager.type import Route, SchemaNode, Link, Tag, LinkType, FieldType, PK, CoreData
@@ -26,6 +28,7 @@ class Voyager:
26
28
  include_tags: list[str] | None = None,
27
29
  module_color: dict[str, str] | None = None,
28
30
  route_name: str | None = None,
31
+ hide_primitive_route: bool = False,
29
32
  load_meta: bool = False
30
33
  ):
31
34
 
@@ -48,6 +51,7 @@ class Voyager:
48
51
  self.module_color = module_color or {}
49
52
  self.route_name = route_name
50
53
  self.load_meta = load_meta
54
+ self.hide_primitive_route = hide_primitive_route
51
55
 
52
56
 
53
57
  def _get_available_route(self, app: FastAPI):
@@ -88,29 +92,37 @@ class Voyager:
88
92
  # filter by route_name (route.id) if provided
89
93
  if self.route_name is not None and route_id != self.route_name:
90
94
  continue
95
+ is_primitive_response = is_non_pydantic_type(route.response_model)
96
+
97
+ # filter primitive route if needed
98
+ if self.hide_primitive_route and is_primitive_response:
99
+ continue
100
+
101
+ self.links.append(Link(
102
+ source=tag_id,
103
+ source_origin=tag_id,
104
+ target=route_id,
105
+ target_origin=route_id,
106
+ type='tag_route'
107
+ ))
91
108
 
92
109
  route_obj = Route(
93
110
  id=route_id,
94
111
  name=route_name,
95
112
  module=route_module,
96
113
  vscode_link=get_vscode_link(route.endpoint) if self.load_meta else '',
97
- source_code=inspect.getsource(route.endpoint) if self.load_meta else ''
114
+ source_code=inspect.getsource(route.endpoint) if self.load_meta else '',
115
+ response_schema=get_type_name(route.response_model),
116
+ is_primitive=is_primitive_response
98
117
  )
99
-
100
118
  self.routes.append(route_obj)
101
119
  # add route into current tag
102
120
  self.tag_set[tag_id].routes.append(route_obj)
103
- self.links.append(Link(
104
- source=tag_id,
105
- source_origin=tag_id,
106
- target=route_id,
107
- target_origin=route_id,
108
- type='tag_route'
109
- ))
110
121
 
111
122
  # add response_models and create links from route -> response_model
112
123
  for schema in get_core_types(route.response_model):
113
124
  if schema and issubclass(schema, BaseModel):
125
+ is_primitive_response = False
114
126
  target_name = full_class_name(schema)
115
127
  self.links.append(Link(
116
128
  source=route_id,
@@ -104,9 +104,6 @@
104
104
  </div>
105
105
  </div>
106
106
 
107
- <div class="col-auto">
108
- <q-toggle class="q-ml-md" v-model="state.brief" label="Brief Mode" title="config module_prefix to enable it" dense />
109
- </div>
110
107
 
111
108
  <!-- <div class="col-auto">
112
109
  <q-btn-dropdown
@@ -129,6 +126,10 @@
129
126
  </div> -->
130
127
 
131
128
  <div class="col-auto q-ml-auto">
129
+ <q-toggle class="q-ml-md" v-model="state.brief" label="Brief Mode" title="config module_prefix to enable it" dense />
130
+ <q-toggle class="q-ml-md" v-model="state.hidePrimitiveRoute" label="Hide Primitive Routes" title="" dense />
131
+ </div>
132
+ <div class="col-auto">
132
133
  <q-btn outline @click="onReset" title="may be very slow" label="Show All" />
133
134
  </div>
134
135
  <div class="col-auto">
@@ -200,7 +201,7 @@
200
201
 
201
202
  <q-list separator>
202
203
  <q-item
203
- v-for="route in (tag.routes || [])"
204
+ v-for="route in (state.hidePrimitiveRoute ? tag.routes.filter(r => !r.is_primitive) :tag.routes || [])"
204
205
  :key="route.id"
205
206
  clickable
206
207
  v-ripple
@@ -209,8 +210,8 @@
209
210
  @click="selectRoute(route.id)"
210
211
  >
211
212
  <q-item-section>
212
- <span class="q-ml-sm"> {{ route.name }} </span>
213
- </q-item-section>
213
+ <span class="q-ml-sm"> <span style="font-weight: bold;">⋅</span> &nbsp; {{ route.name }}</span>
214
+ </q-item-section>
214
215
  </q-item>
215
216
  <q-item v-if="!tag.routes || tag.routes.length === 0" dense>
216
217
  <q-item-section class="text-grey-6">No routes</q-item-section>
@@ -23,6 +23,7 @@ const app = createApp({
23
23
  { label: "All fields", value: "all" },
24
24
  ],
25
25
  brief: false,
26
+ hidePrimitiveRoute: false,
26
27
  generating: false,
27
28
  rawTags: [], // [{ name, routes: [{ id, name }] }]
28
29
  rawSchemas: [], // [{ name, fullname }]
@@ -123,6 +124,7 @@ const app = createApp({
123
124
  route_name: state.routeId || null,
124
125
  show_fields: state.showFields,
125
126
  brief: state.brief,
127
+ hide_primitive_route: state.hidePrimitiveRoute
126
128
  };
127
129
 
128
130
  const res = await fetch("dot", {
@@ -243,7 +245,11 @@ const app = createApp({
243
245
  }
244
246
 
245
247
  function selectRoute(routeId) {
246
- state.routeId = routeId
248
+ if (state.routeId === routeId) {
249
+ state.routeId = ''
250
+ } else {
251
+ state.routeId = routeId
252
+ }
247
253
  onGenerate()
248
254
  }
249
255
 
@@ -276,6 +282,15 @@ const app = createApp({
276
282
  }
277
283
  );
278
284
 
285
+ watch(
286
+ () => state.hidePrimitiveRoute,
287
+ () => {
288
+ if (!state.initializing) {
289
+ onGenerate();
290
+ }
291
+ }
292
+ );
293
+
279
294
  onMounted(async () => {
280
295
  await loadInitial();
281
296
  });
@@ -77,4 +77,8 @@ def get_page_test_1():
77
77
 
78
78
  @app.get("/page_test_2/", tags=['for-page'], response_model=A)
79
79
  def get_page_test_2():
80
- return {}
80
+ return {}
81
+
82
+ @app.get("/page_test_3/", tags=['for-page'], response_model=bool)
83
+ def get_page_test_3():
84
+ return True
@@ -0,0 +1,4 @@
1
+ from fastapi_voyager.server import create_app_with_fastapi
2
+ from tests.demo import app
3
+
4
+ app.mount('/voyager', create_app_with_fastapi(app, module_color={"tests.service": "red"}, module_prefix="tests.service"))
@@ -1,8 +0,0 @@
1
- from fastapi import FastAPI
2
- from fastapi_voyager.server import create_app_with_fastapi
3
- from tests.demo import app as demo_app
4
-
5
- subapp = create_app_with_fastapi(demo_app)
6
-
7
- app = FastAPI()
8
- app.mount("/xxx", subapp)
File without changes
File without changes