fastapi-voyager 0.5.3__py3-none-any.whl → 0.6.1__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/cli.py CHANGED
@@ -169,6 +169,12 @@ Examples:
169
169
  default=8000,
170
170
  help="Port for the preview server when --server is used (default: 8000)"
171
171
  )
172
+ parser.add_argument(
173
+ "--host",
174
+ type=str,
175
+ default="127.0.0.1",
176
+ help="Host/IP for the preview server when --server is used (default: 127.0.0.1). Use 0.0.0.0 to listen on all interfaces."
177
+ )
172
178
 
173
179
  parser.add_argument(
174
180
  "--version", "-v",
@@ -267,8 +273,8 @@ Examples:
267
273
  print("Error: uvicorn is required to run the server. Install via 'pip install uvicorn' or 'uv add uvicorn'.")
268
274
  sys.exit(1)
269
275
  app_server = viz_server.create_app_with_fastapi(app, module_color=module_color)
270
- print(f"Starting preview server at http://127.0.0.1:{args.port} ... (Ctrl+C to stop)")
271
- uvicorn.run(app_server, host="127.0.0.1", port=args.port)
276
+ print(f"Starting preview server at http://{args.host}:{args.port} ... (Ctrl+C to stop)")
277
+ uvicorn.run(app_server, host=args.host, port=args.port)
272
278
  else:
273
279
  # Generate and write dot file locally
274
280
  generate_visualization(
fastapi_voyager/server.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from pathlib import Path
2
2
  from typing import Optional
3
- from fastapi import FastAPI
3
+ from fastapi import FastAPI, APIRouter
4
4
  from starlette.middleware.gzip import GZipMiddleware
5
5
  from pydantic import BaseModel
6
6
  from fastapi.responses import HTMLResponse, PlainTextResponse, JSONResponse
@@ -33,23 +33,13 @@ class Payload(BaseModel):
33
33
  show_fields: str = 'object'
34
34
  show_meta: bool = False
35
35
 
36
- def create_app_with_fastapi(
36
+ def create_route(
37
37
  target_app: FastAPI,
38
38
  module_color: dict[str, str] | None = None,
39
- gzip_minimum_size: int | None = 500,
40
- ) -> FastAPI:
41
- """Create a FastAPI server that serves DOT computed via Analytics.
42
-
43
- This avoids module-level globals by keeping state in closures.
44
- """
45
-
46
- app = FastAPI(title="fastapi-voyager demo server")
39
+ ):
40
+ router = APIRouter(tags=['fastapi-voyager'])
47
41
 
48
- # Enable gzip compression for larger responses (e.g. DOT / schemas payload)
49
- if gzip_minimum_size is not None and gzip_minimum_size >= 0:
50
- app.add_middleware(GZipMiddleware, minimum_size=gzip_minimum_size)
51
-
52
- @app.get("/dot", response_model=OptionParam)
42
+ @router.get("/dot", response_model=OptionParam)
53
43
  def get_dot() -> str:
54
44
  voyager = Voyager(module_color=module_color, load_meta=True)
55
45
  voyager.analysis(target_app)
@@ -71,7 +61,7 @@ def create_app_with_fastapi(
71
61
 
72
62
  return OptionParam(tags=tags, schemas=schemas, dot=dot)
73
63
 
74
- @app.post("/dot", response_class=PlainTextResponse)
64
+ @router.post("/dot", response_class=PlainTextResponse)
75
65
  def get_filtered_dot(payload: Payload) -> str:
76
66
  voyager = Voyager(
77
67
  include_tags=payload.tags,
@@ -85,7 +75,7 @@ def create_app_with_fastapi(
85
75
  voyager.analysis(target_app)
86
76
  return voyager.render_dot()
87
77
 
88
- @app.post("/dot-core-data", response_model=CoreData)
78
+ @router.post("/dot-core-data", response_model=CoreData)
89
79
  def get_filtered_dot_core_data(payload: Payload) -> str:
90
80
  voyager = Voyager(
91
81
  include_tags=payload.tags,
@@ -98,13 +88,13 @@ def create_app_with_fastapi(
98
88
  )
99
89
  voyager.analysis(target_app)
100
90
  return voyager.dump_core_data()
101
-
102
- @app.post('/dot-render-core-data', response_class=PlainTextResponse)
91
+
92
+ @router.post('/dot-render-core-data', response_class=PlainTextResponse)
103
93
  def render_dot_from_core_data(core_data: CoreData) -> str:
104
94
  renderer = Renderer(show_fields=core_data.show_fields, module_color=core_data.module_color, schema=core_data.schema)
105
95
  return renderer.render_dot(core_data.tags, core_data.routes, core_data.nodes, core_data.links)
106
96
 
107
- @app.get("/", response_class=HTMLResponse)
97
+ @router.get("/", response_class=HTMLResponse)
108
98
  def index():
109
99
  index_file = WEB_DIR / "index.html"
110
100
  if index_file.exists():
@@ -120,8 +110,22 @@ def create_app_with_fastapi(
120
110
  </html>
121
111
  """
122
112
 
123
- # Serve static files under /static
124
- app.mount("/static", StaticFiles(directory=str(WEB_DIR)), name="static")
113
+ return router
114
+
115
+
116
+ def create_app_with_fastapi(
117
+ target_app: FastAPI,
118
+ module_color: dict[str, str] | None = None,
119
+ gzip_minimum_size: int | None = 500,
120
+ ) -> FastAPI:
121
+ router = create_route(target_app, module_color=module_color)
122
+
123
+ app = FastAPI(title="fastapi-voyager demo server")
124
+ if gzip_minimum_size is not None and gzip_minimum_size >= 0:
125
+ app.add_middleware(GZipMiddleware, minimum_size=gzip_minimum_size)
126
+
127
+ app.mount("/fastapi-voyager-static", StaticFiles(directory=str(WEB_DIR)), name="static")
128
+ app.include_router(router)
125
129
 
126
130
  return app
127
131
 
@@ -142,7 +142,7 @@ def get_type_name(anno):
142
142
 
143
143
 
144
144
  def is_inheritance_of_pydantic_base(cls):
145
- return issubclass(cls, BaseModel) and cls is not BaseModel
145
+ return safe_issubclass(cls, BaseModel) and cls is not BaseModel
146
146
 
147
147
 
148
148
  def get_bases_fields(schemas: list[type[BaseModel]]) -> set[str]:
@@ -228,6 +228,7 @@ def safe_issubclass(kls, classinfo):
228
228
  try:
229
229
  return issubclass(kls, classinfo)
230
230
  except TypeError:
231
+ print(kls.__name__, 'is not a class')
231
232
  return False
232
233
 
233
234
 
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.5.3"
2
+ __version__ = "0.6.1"
@@ -31,7 +31,7 @@ export default defineComponent({
31
31
  if (!props.coreData) return;
32
32
  loading.value = true;
33
33
  try {
34
- const res = await fetch("/dot-render-core-data", {
34
+ const res = await fetch("dot-render-core-data", {
35
35
  method: "POST",
36
36
  headers: { "Content-Type": "application/json" },
37
37
  body: JSON.stringify(props.coreData),
@@ -81,7 +81,7 @@ export default defineComponent({
81
81
  schema_field: state.fieldName || null,
82
82
  show_fields: state.showFields,
83
83
  };
84
- const res = await fetch("/dot", {
84
+ const res = await fetch("dot", {
85
85
  method: "POST",
86
86
  headers: { "Content-Type": "application/json" },
87
87
  body: JSON.stringify(payload),
@@ -2,14 +2,14 @@
2
2
  <head>
3
3
  <title>FastAPI Voyager</title>
4
4
  <meta name="theme-color" content="#ffffff" />
5
- <link rel="stylesheet" href="/static/graphviz.svg.css" />
6
- <link rel="stylesheet" href="/static/quasar.min.css" />
5
+ <link rel="stylesheet" href="fastapi-voyager-static/graphviz.svg.css" />
6
+ <link rel="stylesheet" href="fastapi-voyager-static/quasar.min.css" />
7
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" />
8
+ <link rel="apple-touch-icon" sizes="180x180" href="fastapi-voyager-static/icon/apple-touch-icon.png" />
9
+ <link rel="icon" type="image/png" sizes="32x32" href="fastapi-voyager-static/icon/favicon-32x32.png" />
10
+ <link rel="icon" type="image/png" sizes="16x16" href="fastapi-voyager-static/icon/favicon-16x16.png" />
11
+ <link rel="icon" href="fastapi-voyager-static/icon/favicon.ico" sizes="any" />
12
+ <link rel="manifest" href="fastapi-voyager-static/icon/site.webmanifest" />
13
13
  <link
14
14
  href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons"
15
15
  rel="stylesheet"
@@ -265,8 +265,8 @@
265
265
 
266
266
  <!-- Add the following at the end of your body tag -->
267
267
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.5.22/vue.global.prod.min.js" integrity="sha512-Y9sKU0AwzWRxKSLd2i35LuDpUdHY/E9tJrKG0mxw0qYQ75VVgGYazIUQPwKhFK9vGO3jIgAtxLiSq8GQ7PDfUg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
268
- <script src="/static/quasar.min.js"></script>
269
- <script src="/static/graphviz.svg.js"></script>
268
+ <script src="fastapi-voyager-static/quasar.min.js"></script>
269
+ <script src="fastapi-voyager-static/graphviz.svg.js"></script>
270
270
  <!-- highlight.js minimal ES module load (python only) -->
271
271
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css" />
272
272
  <script type="module">
@@ -275,6 +275,6 @@
275
275
  hljs.registerLanguage('python', python);
276
276
  window.hljs = hljs;
277
277
  </script>
278
- <script type="module" src="/static/vue-main.js"></script>
278
+ <script type="module" src="fastapi-voyager-static/vue-main.js"></script>
279
279
  </body>
280
280
  </html>
@@ -37,8 +37,8 @@ const app = createApp({
37
37
  const dumpJson = ref("");
38
38
  const showImportDialog = ref(false);
39
39
  const importJsonText = ref("");
40
- const showRenderGraph = ref(false);
41
- const renderCoreData = ref(null);
40
+ const showRenderGraph = ref(false);
41
+ const renderCoreData = ref(null);
42
42
  const schemaName = ref(""); // used by detail dialog
43
43
  const schemaFieldFilterSchema = ref(null); // external schemaName for schema-field-filter
44
44
  const schemaCodeName = ref("");
@@ -94,7 +94,7 @@ const app = createApp({
94
94
  async function loadInitial() {
95
95
  state.initializing = true;
96
96
  try {
97
- const res = await fetch("/dot");
97
+ const res = await fetch("dot");
98
98
  const data = await res.json();
99
99
  state.rawTags = Array.isArray(data.tags) ? data.tags : [];
100
100
  state.rawSchemasFull = Array.isArray(data.schemas) ? data.schemas : [];
@@ -134,7 +134,7 @@ const app = createApp({
134
134
  show_fields: state.showFields,
135
135
  };
136
136
 
137
- const res = await fetch("/dot", {
137
+ const res = await fetch("dot", {
138
138
  method: "POST",
139
139
  headers: { "Content-Type": "application/json" },
140
140
  body: JSON.stringify(payload),
@@ -180,7 +180,7 @@ const app = createApp({
180
180
  route_name: state.routeId || null,
181
181
  show_fields: state.showFields,
182
182
  };
183
- const res = await fetch("/dot-core-data", {
183
+ const res = await fetch("dot-core-data", {
184
184
  method: "POST",
185
185
  headers: { "Content-Type": "application/json" },
186
186
  body: JSON.stringify(payload),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.5.3
3
+ Version: 0.6.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
@@ -1,24 +1,24 @@
1
1
  fastapi_voyager/__init__.py,sha256=E5WTV_sYs2LK8I6jzA7AuvFU5a8_vjnDseC3DMha0iQ,149
2
- fastapi_voyager/cli.py,sha256=scBD2ojOq0_sJ8Usu79MoGUvkEc_zlnBO6xK0grz7dI,10478
2
+ fastapi_voyager/cli.py,sha256=wWI0YEB7DaCfK6PkkEMOh3VxXGPV92NN8x-bB354Njs,10705
3
3
  fastapi_voyager/filter.py,sha256=uZrVVMhHG5E7j1wdsiB02RAyoDdF1q8A4J04oCboYAU,4644
4
4
  fastapi_voyager/module.py,sha256=Z2QHNmiLk6ZAJlm2nSmO875Q33TweSg8UxZSzIpU9zY,3499
5
5
  fastapi_voyager/render.py,sha256=ctwad-KNbFajhgnA8OI8412s6s67UbV-dvZFXBt_Ssg,7410
6
- fastapi_voyager/server.py,sha256=Eer6GdD9-EG9QGHlYmClF3MeVxw68amjK4iW_YZ5ShI,3751
6
+ fastapi_voyager/server.py,sha256=6pDFrVd4AZP3KaqukJS7xq_f7ar4gLkb6XhSO5zoW_A,3782
7
7
  fastapi_voyager/type.py,sha256=nad4WNxTcZFi7Mskw6p2W7v2Gs4f0giVLNoFjZlKmbA,1778
8
- fastapi_voyager/type_helper.py,sha256=j7AiFXsfl4kaxshYtofbsqo08dIXiHvJ190soIzUdLk,8380
9
- fastapi_voyager/version.py,sha256=Hb2z9BH1asz5RSe-xgzQIT7VN25qyDUyXYTS-6rOm5g,48
8
+ fastapi_voyager/type_helper.py,sha256=aYfuAyagOTpMrgjAfkfyXsOkIJckh9AUun8OnIPUlnE,8431
9
+ fastapi_voyager/version.py,sha256=6hO5IfIQdb_NZWiIujWhR-Wpo8LK2XAwUI_Ioi7ol9g,48
10
10
  fastapi_voyager/voyager.py,sha256=qMXZrQsmUiBljhOFOUtXV--a5i7THz9l00UNoxDu_0w,10193
11
11
  fastapi_voyager/web/graph-ui.js,sha256=eEjDnJVMvk35LdRoxcqX_fZxLFS9_bUrGAZL6K2O5C0,4176
12
12
  fastapi_voyager/web/graphviz.svg.css,sha256=zDCjjpT0Idufu5YOiZI76PL70-avP3vTyzGPh9M85Do,1563
13
13
  fastapi_voyager/web/graphviz.svg.js,sha256=lvAdbjHc-lMSk4GQp-iqYA2PCFX4RKnW7dFaoe0LUHs,16005
14
- fastapi_voyager/web/index.html,sha256=vndU6K9BN5f75OMPPPzREF7xACmf31wTVyGuOYksiys,10461
14
+ fastapi_voyager/web/index.html,sha256=hRbsdraGUZYB1dP_FIifyhp6ZqT0VyoNE-U3S4lCRaQ,10611
15
15
  fastapi_voyager/web/quasar.min.css,sha256=F5jQe7X2XT54VlvAaa2V3GsBFdVD-vxDZeaPLf6U9CU,203145
16
16
  fastapi_voyager/web/quasar.min.js,sha256=h0ftyPMW_CRiyzeVfQqiup0vrVt4_QWojpqmpnpn07E,502974
17
- fastapi_voyager/web/vue-main.js,sha256=tW0jRSSABMmnAqLDaIXMeXQBm0WWOKycsYesgg8ArZw,8798
18
- fastapi_voyager/web/component/render-graph.js,sha256=8jfN-ik7Ckn5Frx01umjlYqP6i0HELDCcWQMp5zbIhI,2323
17
+ fastapi_voyager/web/vue-main.js,sha256=twafDl_vDIRjlY0Oltslg2_UAO4L1fezKxuKszvnbjU,8799
18
+ fastapi_voyager/web/component/render-graph.js,sha256=e8Xgh2Kl-nYU0P1gstEmAepCgFnk2J6UdxW8TlMafGs,2322
19
19
  fastapi_voyager/web/component/route-code-display.js,sha256=NECC1OGcPCdDfbghtRJEnmFM6HmH5J3win2ibapWPeA,2649
20
20
  fastapi_voyager/web/component/schema-code-display.js,sha256=oOusgTvCaWGnoKb-NBwu0SXqJJf2PTUtp3lUczokTBM,5515
21
- fastapi_voyager/web/component/schema-field-filter.js,sha256=9WBjO6JJl2yf6OiiXoddMgvL32qTDu0PM-RxkkJ7t5M,6267
21
+ fastapi_voyager/web/component/schema-field-filter.js,sha256=5lK2mdgp7_UWcwURi9djRCkIwih-3f4EmDbhKFuLBDc,6266
22
22
  fastapi_voyager/web/icon/android-chrome-192x192.png,sha256=35sBy6jmUFJCcquStaafHH1qClZIbd-X3PIKSeLkrNo,37285
23
23
  fastapi_voyager/web/icon/android-chrome-512x512.png,sha256=eb2eDjCwIruc05029_0L9hcrkVkv8KceLn1DJMYU0zY,210789
24
24
  fastapi_voyager/web/icon/apple-touch-icon.png,sha256=gnWK46tPnvSw1-oYZjgI02wpoO4OrIzsVzGHC5oKWO0,33187
@@ -26,8 +26,8 @@ fastapi_voyager/web/icon/favicon-16x16.png,sha256=JC07jEzfIYxBIoQn_FHXvyHuxESdhW
26
26
  fastapi_voyager/web/icon/favicon-32x32.png,sha256=C7v1h58cfWOsiLp9yOIZtlx-dLasBcq3NqpHVGRmpt4,1859
27
27
  fastapi_voyager/web/icon/favicon.ico,sha256=tZolYIXkkBcFiYl1A8ksaXN2VjGamzcSdes838dLvNc,15406
28
28
  fastapi_voyager/web/icon/site.webmanifest,sha256=ep4Hzh9zhmiZF2At3Fp1dQrYQuYF_3ZPZxc1KcGBvwQ,263
29
- fastapi_voyager-0.5.3.dist-info/METADATA,sha256=TFMnB94SxSoEblutrjAYkSqopvPgeY5zMsMJhH86_KI,6878
30
- fastapi_voyager-0.5.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
- fastapi_voyager-0.5.3.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
32
- fastapi_voyager-0.5.3.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
33
- fastapi_voyager-0.5.3.dist-info/RECORD,,
29
+ fastapi_voyager-0.6.1.dist-info/METADATA,sha256=AQ82S1IvplYc5zFJT91-IPDkKSR3FpRAAx-GgAz-7hg,6878
30
+ fastapi_voyager-0.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ fastapi_voyager-0.6.1.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
32
+ fastapi_voyager-0.6.1.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
33
+ fastapi_voyager-0.6.1.dist-info/RECORD,,