fastapi-voyager 0.11.9__py3-none-any.whl → 0.11.11__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
@@ -1,15 +1,18 @@
1
1
  """Command line interface for fastapi-voyager."""
2
2
  import argparse
3
- import sys
4
- import importlib.util
5
3
  import importlib
4
+ import importlib.util
5
+ import logging
6
6
  import os
7
+ import sys
7
8
  from typing import Optional
8
9
 
9
10
  from fastapi import FastAPI
10
- from fastapi_voyager.voyager import Voyager
11
- from fastapi_voyager.version import __version__
12
11
  from fastapi_voyager import server as viz_server
12
+ from fastapi_voyager.version import __version__
13
+ from fastapi_voyager.voyager import Voyager
14
+
15
+ logger = logging.getLogger(__name__)
13
16
 
14
17
 
15
18
  def load_fastapi_app_from_file(module_path: str, app_name: str = "app") -> Optional[FastAPI]:
@@ -22,7 +25,7 @@ def load_fastapi_app_from_file(module_path: str, app_name: str = "app") -> Optio
22
25
  # Load the module
23
26
  spec = importlib.util.spec_from_file_location("app_module", module_path)
24
27
  if spec is None or spec.loader is None:
25
- print(f"Error: Could not load module from {module_path}")
28
+ logger.error(f"Could not load module from {module_path}")
26
29
  return None
27
30
 
28
31
  module = importlib.util.module_from_spec(spec)
@@ -34,15 +37,13 @@ def load_fastapi_app_from_file(module_path: str, app_name: str = "app") -> Optio
34
37
  app = getattr(module, app_name)
35
38
  if isinstance(app, FastAPI):
36
39
  return app
37
- else:
38
- print(f"Error: '{app_name}' is not a FastAPI instance")
39
- return None
40
- else:
41
- print(f"Error: No attribute '{app_name}' found in the module")
40
+ logger.error(f"'{app_name}' is not a FastAPI instance")
42
41
  return None
42
+ logger.error(f"No attribute '{app_name}' found in the module")
43
+ return None
43
44
 
44
45
  except Exception as e:
45
- print(f"Error loading FastAPI app: {e}")
46
+ logger.error(f"Error loading FastAPI app: {e}")
46
47
  return None
47
48
 
48
49
 
@@ -66,22 +67,20 @@ def load_fastapi_app_from_module(module_name: str, app_name: str = "app") -> Opt
66
67
  app = getattr(module, app_name)
67
68
  if isinstance(app, FastAPI):
68
69
  return app
69
- else:
70
- print(f"Error: '{app_name}' is not a FastAPI instance")
71
- return None
72
- else:
73
- print(f"Error: No attribute '{app_name}' found in module '{module_name}'")
70
+ logger.error(f"'{app_name}' is not a FastAPI instance")
74
71
  return None
72
+ logger.error(f"No attribute '{app_name}' found in module '{module_name}'")
73
+ return None
75
74
  finally:
76
75
  # Cleanup: if we added the path, remove it
77
76
  if path_added and current_dir in sys.path:
78
77
  sys.path.remove(current_dir)
79
78
 
80
79
  except ImportError as e:
81
- print(f"Error: Could not import module '{module_name}': {e}")
80
+ logger.error(f"Could not import module '{module_name}': {e}")
82
81
  return None
83
82
  except Exception as e:
84
- print(f"Error loading FastAPI app from module '{module_name}': {e}")
83
+ logger.error(f"Error loading FastAPI app from module '{module_name}': {e}")
85
84
  return None
86
85
 
87
86
 
@@ -110,9 +109,9 @@ def generate_visualization(
110
109
  # Optionally write to file
111
110
  with open(output_file, 'w', encoding='utf-8') as f:
112
111
  f.write(dot_content)
113
- print(f"DOT file generated: {output_file}")
114
- print("To render the graph, use: dot -Tpng router_viz.dot -o router_viz.png")
115
- print("Or view online: https://dreampuf.github.io/GraphvizOnline/")
112
+ logger.info(f"DOT file generated: {output_file}")
113
+ logger.info("To render the graph, use: dot -Tpng router_viz.dot -o router_viz.png")
114
+ logger.info("Or view online: https://dreampuf.github.io/GraphvizOnline/")
116
115
 
117
116
 
118
117
  def main():
@@ -217,41 +216,30 @@ Examples:
217
216
  help="Filter by route id (format: <endpoint>_<path with _>)"
218
217
  )
219
218
  parser.add_argument(
220
- "--demo",
221
- action="store_true",
222
- help="Run built-in demo (equivalent to: --module tests.demo --server --module_color=tests.service:blue --module_color=tests.demo:tomato)"
219
+ "--log-level",
220
+ dest="log_level",
221
+ default="INFO",
222
+ help="Logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL (default: INFO)"
223
223
  )
224
224
 
225
225
  args = parser.parse_args()
226
226
 
227
- # Handle demo mode: override module_name and defaults
228
- if args.demo:
229
- # Force module loading path
230
- args.module_name = "tests.demo"
231
- # Ensure server mode on
232
- args.server = True
233
- # Inject default module colors if absent / merge
234
- demo_defaults = ["tests.service:blue", "tests.demo:tomato"]
235
- existing = set(args.module_color or [])
236
- for d in demo_defaults:
237
- # only add if same key not already provided
238
- key = d.split(":", 1)[0]
239
- if not any(mc.startswith(key + ":") for mc in existing):
240
- args.module_color = (args.module_color or []) + [d]
241
-
242
227
  if args.module_prefix and not args.server:
243
228
  parser.error("--module_prefix can only be used together with --server")
244
229
 
245
- # Validate required target if not demo
246
- if not args.demo and not (args.module_name or args.module):
247
- parser.error("You must provide a module file, -m module name, or use --demo")
230
+ if not (args.module_name or args.module):
231
+ parser.error("You must provide a module file, -m module name")
232
+
233
+ # Configure logging based on --log-level
234
+ level_name = (args.log_level or "INFO").upper()
235
+ logging.basicConfig(level=level_name)
248
236
 
249
237
  # Load FastAPI app based on the input method (module_name takes precedence)
250
238
  if args.module_name:
251
239
  app = load_fastapi_app_from_module(args.module_name, args.app)
252
240
  else:
253
241
  if not os.path.exists(args.module):
254
- print(f"Error: File '{args.module}' not found")
242
+ logger.error(f"File '{args.module}' not found")
255
243
  sys.exit(1)
256
244
  app = load_fastapi_app_from_file(args.module, args.app)
257
245
 
@@ -279,15 +267,15 @@ Examples:
279
267
  try:
280
268
  import uvicorn
281
269
  except ImportError:
282
- print("Error: uvicorn is required to run the server. Install via 'pip install uvicorn' or 'uv add uvicorn'.")
270
+ logger.info("uvicorn is required to run the server. Install via 'pip install uvicorn' or 'uv add uvicorn'.")
283
271
  sys.exit(1)
284
272
  app_server = viz_server.create_voyager(
285
273
  app,
286
274
  module_color=module_color,
287
275
  module_prefix=args.module_prefix,
288
276
  )
289
- print(f"Starting preview server at http://{args.host}:{args.port} ... (Ctrl+C to stop)")
290
- uvicorn.run(app_server, host=args.host, port=args.port)
277
+ logger.info(f"Starting preview server at http://{args.host}:{args.port} ... (Ctrl+C to stop)")
278
+ uvicorn.run(app_server, host=args.host, port=args.port, log_level=level_name.lower())
291
279
  else:
292
280
  # Generate and write dot file locally
293
281
  generate_visualization(
@@ -300,7 +288,7 @@ Examples:
300
288
  route_name=args.route_name,
301
289
  )
302
290
  except Exception as e:
303
- print(f"Error generating visualization: {e}")
291
+ logger.info(f"Error generating visualization: {e}")
304
292
  sys.exit(1)
305
293
 
306
294
 
fastapi_voyager/filter.py CHANGED
@@ -236,7 +236,6 @@ def filter_subgraph_from_tag_to_schema_by_module_prefix(
236
236
  seen_pairs: set[tuple[str, str]] = set()
237
237
 
238
238
  for link in tag_route_links:
239
- # print(link)
240
239
  tag_id = link.source_origin
241
240
  start_node_id = link.target_origin
242
241
  if tag_id is None or start_node_id is None:
fastapi_voyager/render.py CHANGED
@@ -1,6 +1,9 @@
1
1
  from typing import Optional
2
2
  from fastapi_voyager.type import SchemaNode, ModuleNode, Link, Tag, Route, FieldType, PK, ModuleRoute
3
3
  from fastapi_voyager.module import build_module_schema_tree, build_module_route_tree
4
+ from logging import getLogger
5
+
6
+ logger = getLogger(__name__)
4
7
 
5
8
 
6
9
  class Renderer:
@@ -17,7 +20,10 @@ class Renderer:
17
20
  self.schema = schema
18
21
  self.show_module = show_module
19
22
 
20
- def render_schema_label(self, node: SchemaNode) -> str:
23
+ logger.info(f'show_module: {self.show_module}')
24
+ logger.info(f'module_color: {self.module_color}')
25
+
26
+ def render_schema_label(self, node: SchemaNode, color: Optional[str]=None) -> str:
21
27
  has_base_fields = any(f.from_base for f in node.fields)
22
28
  fields = [n for n in node.fields if n.from_base is False]
23
29
 
@@ -38,7 +44,8 @@ class Renderer:
38
44
  field_str = f"""<tr><td align="left" port="f{field.name}" cellpadding="8"><font> {display_xml} </font></td></tr>"""
39
45
  fields_parts.append(field_str)
40
46
 
41
- header_color = 'tomato' if node.id == self.schema else '#009485'
47
+ default_color = '#009485' if color is None else color
48
+ header_color = 'tomato' if node.id == self.schema else default_color
42
49
  header = f"""<tr><td cellpadding="6" bgcolor="{header_color}" align="center" colspan="1" port="{PK}"> <font color="white"> {node.name} </font></td> </tr>"""
43
50
  field_content = ''.join(fields_parts) if fields_parts else ''
44
51
  return f"""<<table border="1" cellborder="0" cellpadding="0" bgcolor="white"> {header} {field_content} </table>>"""
@@ -67,43 +74,56 @@ class Renderer:
67
74
  raise ValueError(f'Unknown link type: {link.type}')
68
75
 
69
76
  def render_module_schema_content(self, nodes: list[SchemaNode]) -> str:
70
- def render_node(node: SchemaNode) -> str:
77
+ def render_node(node: SchemaNode, color: Optional[str]=None) -> str:
71
78
  return f'''
72
79
  "{node.id}" [
73
- label = {self.render_schema_label(node)}
80
+ label = {self.render_schema_label(node, color)}
74
81
  shape = "plain"
75
82
  margin="0.5,0.1"
76
83
  ];'''
77
- def render_module_schema(mod: ModuleNode) -> str:
78
- color: Optional[str] = None
79
84
 
85
+ def render_module_schema(mod: ModuleNode, inherit_color: Optional[str]=None, show_cluster:bool=True) -> str:
86
+ color: Optional[str] = inherit_color
87
+
88
+ # recursively vist module from short to long: 'a', 'a.b', 'a.b.c'
89
+ # color_flag: {'a', 'a.b.c'}
90
+ # at first 'a', match 'a' -> color, remove 'a' from color_flag
91
+ # at 'a.b', no match
92
+ # at 'a.b.c', match 'a.b.c' -> color, remove 'a.b.c' from color_flag
80
93
  for k in module_color_flag:
81
- if mod.fullname.startswith(k):
94
+ if mod.fullname.startswith(k):
82
95
  module_color_flag.remove(k)
83
96
  color = self.module_color[k]
84
97
  break
85
98
 
86
- inner_nodes = [ render_node(node) for node in mod.schema_nodes ]
99
+ inner_nodes = [ render_node(node, color) for node in mod.schema_nodes ]
87
100
  inner_nodes_str = '\n'.join(inner_nodes)
88
- child_str = '\n'.join(render_module_schema(m) for m in mod.modules)
89
- return f'''
90
- subgraph cluster_module_{mod.fullname.replace('.', '_')} {{
91
- tooltip="{mod.fullname}"
92
- color = "#666"
93
- style="rounded"
94
- label = " {mod.name}"
95
- labeljust = "l"
96
- {(f'pencolor = "{color}"' if color else 'pencolor="#ccc"')}
97
- {(f'penwidth = 3' if color else 'penwidth=""')}
101
+ child_str = '\n'.join(render_module_schema(mod=m, inherit_color=color, show_cluster=show_cluster) for m in mod.modules)
102
+
103
+ if show_cluster:
104
+ return f'''
105
+ subgraph cluster_module_{mod.fullname.replace('.', '_')} {{
106
+ tooltip="{mod.fullname}"
107
+ color = "#666"
108
+ style="rounded"
109
+ label = " {mod.name}"
110
+ labeljust = "l"
111
+ {(f'pencolor = "{color}"' if color else 'pencolor="#ccc"')}
112
+ {(f'penwidth = 3' if color else 'penwidth=""')}
113
+ {inner_nodes_str}
114
+ {child_str}
115
+ }}'''
116
+ else:
117
+ return f'''
98
118
  {inner_nodes_str}
99
119
  {child_str}
100
- }}'''
101
- if self.show_module:
102
- module_schemas = build_module_schema_tree(nodes)
103
- module_color_flag = set(self.module_color.keys())
104
- return '\n'.join(render_module_schema(m) for m in module_schemas)
105
- else:
106
- return '\n'.join(render_node(n) for n in nodes)
120
+ '''
121
+
122
+ # if self.show_module:
123
+ module_schemas = build_module_schema_tree(nodes)
124
+ module_color_flag = set(self.module_color.keys())
125
+ return '\n'.join(render_module_schema(mod=m, show_cluster=self.show_module) for m in module_schemas)
126
+
107
127
 
108
128
  def render_module_route_content(self, routes: list[Route]) -> str:
109
129
  def render_route(route: Route) -> str:
@@ -115,29 +135,32 @@ class Renderer:
115
135
  shape = "record"
116
136
  ];'''
117
137
 
118
- def render_module_route(mod: ModuleRoute) -> str:
138
+ def render_module_route(mod: ModuleRoute, show_cluster: bool=True) -> str:
119
139
  # Inner route nodes, same style as flat route_str
120
140
  inner_nodes = [
121
141
  render_route(r) for r in mod.routes
122
142
  ]
123
143
  inner_nodes_str = '\n'.join(inner_nodes)
124
- child_str = '\n'.join(render_module_route(m) for m in mod.modules)
125
- return f'''
126
- subgraph cluster_route_module_{mod.fullname.replace('.', '_')} {{
127
- tooltip="{mod.fullname}"
128
- color = "#666"
129
- style="rounded"
130
- label = " {mod.name}"
131
- labeljust = "l"
144
+ child_str = '\n'.join(render_module_route(m, show_cluster=show_cluster) for m in mod.modules)
145
+ if show_cluster:
146
+ return f'''
147
+ subgraph cluster_route_module_{mod.fullname.replace('.', '_')} {{
148
+ tooltip="{mod.fullname}"
149
+ color = "#666"
150
+ style="rounded"
151
+ label = " {mod.name}"
152
+ labeljust = "l"
153
+ {inner_nodes_str}
154
+ {child_str}
155
+ }}'''
156
+ else:
157
+ return f'''
132
158
  {inner_nodes_str}
133
159
  {child_str}
134
- }}'''
135
- if self.show_module:
136
- module_routes = build_module_route_tree(routes)
137
- module_routes_str = '\n'.join(render_module_route(m) for m in module_routes)
138
- return module_routes_str
139
- else:
140
- return '\n'.join(render_route(r) for r in routes)
160
+ '''
161
+ module_routes = build_module_route_tree(routes)
162
+ module_routes_str = '\n'.join(render_module_route(m, show_cluster=self.show_module) for m in module_routes)
163
+ return module_routes_str
141
164
 
142
165
 
143
166
  def render_dot(self, tags: list[Tag], routes: list[Route], nodes: list[SchemaNode], links: list[Link], spline_line=False) -> str:
@@ -1,4 +1,5 @@
1
1
  import inspect
2
+ import logging
2
3
  import os
3
4
  from pydantic import BaseModel
4
5
  from typing import get_origin, get_args, Union, Annotated, Any, Type, Generic, Optional
@@ -6,6 +7,8 @@ from fastapi_voyager.type import FieldInfo
6
7
  from types import UnionType
7
8
  import pydantic_resolve.constant as const
8
9
 
10
+ logger = logging.getLogger(__name__)
11
+
9
12
  # Python <3.12 compatibility: TypeAliasType exists only from 3.12 (PEP 695)
10
13
  try: # pragma: no cover - import guard
11
14
  from typing import TypeAliasType # type: ignore
@@ -228,31 +231,27 @@ def get_source(kls):
228
231
  return "failed to get source"
229
232
 
230
233
 
231
- def safe_issubclass(kls, classinfo):
234
+ def safe_issubclass(kls, target_kls):
232
235
  try:
233
- return issubclass(kls, classinfo)
236
+ return issubclass(kls, target_kls)
234
237
  except TypeError:
235
- print(kls.__name__, 'is not a class')
238
+ logger.debug(f'{kls.__module__}:{kls.__qualname__} is not subclass of {target_kls.__module__}:{target_kls.__qualname__}')
236
239
  return False
237
240
 
238
241
 
239
242
  def update_forward_refs(kls):
240
243
  # TODO: refactor
241
- def update_pydantic_forward_refs(kls2: Type[BaseModel]):
244
+ def update_pydantic_forward_refs(pydantic_kls: Type[BaseModel]):
242
245
  """
243
246
  recursively update refs.
244
247
  """
245
248
 
246
- kls2.model_rebuild()
247
- setattr(kls2, const.PYDANTIC_FORWARD_REF_UPDATED, True)
249
+ pydantic_kls.model_rebuild()
250
+ setattr(pydantic_kls, const.PYDANTIC_FORWARD_REF_UPDATED, True)
248
251
 
249
- values = kls2.model_fields.values()
252
+ values = pydantic_kls.model_fields.values()
250
253
  for field in values:
251
254
  update_forward_refs(field.annotation)
252
-
253
- if safe_issubclass(kls, BaseModel):
254
- kls.model_rebuild()
255
- setattr(kls, const.PYDANTIC_FORWARD_REF_UPDATED, True)
256
255
 
257
256
  for shelled_type in get_core_types(kls):
258
257
  if getattr(shelled_type, const.PYDANTIC_FORWARD_REF_UPDATED, False):
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.11.9"
2
+ __version__ = "0.11.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.11.9
3
+ Version: 0.11.11
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
@@ -52,8 +52,11 @@ uv add fastapi-voyager
52
52
  voyager -m path.to.your.app.module --server
53
53
  ```
54
54
 
55
- > *sub_app* is not supported yet.
55
+ > [Sub-Application mounts](https://fastapi.tiangolo.com/advanced/sub-applications/) are not supported yet, but you can specify the name of the FastAPI application used with `--app`. Only a single application (default: 'app') can be selected, but in a scenario where `api` is attached through `app.mount("/api", api)`, you can select `api` like this:
56
56
 
57
+ ```shell
58
+ voyager -m path.to.your.app.module --server --app api
59
+ ```
57
60
 
58
61
  ## Mount into project
59
62
 
@@ -141,6 +144,8 @@ voyager -m tests.demo --module_color=tests.demo:red --module_color=tests.service
141
144
  voyager -m tests.demo -o my_visualization.dot
142
145
 
143
146
  voyager --version
147
+
148
+ voyager --help
144
149
  ```
145
150
 
146
151
  The tool will generate a DOT file that you can render using Graphviz:
@@ -166,8 +171,6 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
166
171
  - [ ] user can generate nodes/edges manually and connect to generated ones
167
172
  - [ ] eg: add owner
168
173
  - [ ] add extra info for schema
169
- - [ ] display standard ER diagram `hard`
170
- - [ ] display potential invalid links
171
174
  - [ ] optimize static resource (allow manually config url)
172
175
  - [ ] improve search dialog
173
176
  - [ ] add route/tag list
@@ -178,11 +181,9 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
178
181
  ### in analysis
179
182
  - [ ] click field to highlight links
180
183
  - [ ] animation effect for edges
181
- - [ ] customrized right click panel
182
- - [ ] show own dependencies
183
- - [ ] sort field name
184
- - [ ] set max limit for fields
185
- - [ ] logging information
184
+ - [ ] display standard ER diagram spec. `hard but important`
185
+ - [ ] display potential invalid links
186
+ - [ ] highlight relationship belongs to ER diagram
186
187
 
187
188
  ### plan:
188
189
  #### <0.9:
@@ -277,15 +278,30 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
277
278
  - [x] fix swagger link in another way
278
279
  - 0.11.9
279
280
  - [x] replace issubclass with safe_issubclass to prevent exception.
281
+ - 0.11.10
282
+ - [x] fix bug during updating forward refs
283
+ - 0.11.11
284
+ - [x] replace print with logging and add `--log-level` in cli, by default info
285
+ - [x] fill node title color with module color
286
+ - [x] optimize cluster render logic
287
+
288
+ ### 0.12
289
+ - 0.12.1
290
+ - [ ] sort tag / route names in left panel
291
+ - [ ] sort field name in nodes
292
+ - [ ] set max limit for fields in nodes
293
+ - [ ] upgrade network algorithm (optional)
294
+ - [ ] refactor render.py
280
295
 
281
- #### 0.12
282
- - [ ] add tests
283
- - [ ] integration with pydantic-resolve
284
- - [ ] show hint for resolve, post fields
285
- - [ ] display loader as edges
296
+ #### 0.13
297
+ - 0.12.0
298
+ - [ ] integration with pydantic-resolve
299
+ - [ ] show hint for resolve, post fields
300
+ - [ ] display loader as edges
301
+ - [ ] add tests
286
302
 
287
303
  #### 0.13
288
- - [ ] config release pipeline
304
+ placeholder
289
305
 
290
306
 
291
307
  ## About pydantic-resolve
@@ -1,12 +1,12 @@
1
1
  fastapi_voyager/__init__.py,sha256=tZy0Nkj8kTaMgbvHy-mGxVcFGVX0Km-36dnzsAIG2uk,230
2
- fastapi_voyager/cli.py,sha256=kQb4g6JEGZR99e5r8LyFFEeb_-uT-n_gp_sDoYG3R7k,11118
3
- fastapi_voyager/filter.py,sha256=GY2J9Vfsf_wbFwC-0t74-Lf-OlO77PnhEXD_rmgkfSw,11574
2
+ fastapi_voyager/cli.py,sha256=xK8DT-m2qP38FK2dGhLP-sHEuS29SBw6ACrnX9w85P0,10521
3
+ fastapi_voyager/filter.py,sha256=9Y-NepveIiCLOI-5eXk6DNK9H3dr5_h4xUbWYHkbo7M,11552
4
4
  fastapi_voyager/module.py,sha256=Z2QHNmiLk6ZAJlm2nSmO875Q33TweSg8UxZSzIpU9zY,3499
5
- fastapi_voyager/render.py,sha256=vdwqIync2wsP8gMPY0v_XjRhdPBtbKyRT8yTBa_Ep3Y,8744
5
+ fastapi_voyager/render.py,sha256=8hVsEDQi2-aP3QKN6KI3RnNz0uG-FuDr_k4D7QNsdQQ,9823
6
6
  fastapi_voyager/server.py,sha256=G48St-leUcEwshIhTYVotxuFWXDAvzjthOCK9AKh9dI,6497
7
7
  fastapi_voyager/type.py,sha256=VmcTB1G-LOT70EWCzi4LU_FUkSGWUIBJX15T_J5HnOo,1764
8
- fastapi_voyager/type_helper.py,sha256=uJI3UQHJ8zcJq_QBnU9FtHl8m2XKTU6ATOhj6IIP91U,9482
9
- fastapi_voyager/version.py,sha256=Wb6eX7VamWPEx6nEYtqHwXME7cHmNHnzkrPw148hvJk,49
8
+ fastapi_voyager/type_helper.py,sha256=TqtYP2_54aar_iQjD0XhjJPXYhfi6icnPPrxkj0a4sk,9523
9
+ fastapi_voyager/version.py,sha256=PokgCRzjnyxlFdVF1p-f93rdL31U6_AVnSKLvGGed9Y,50
10
10
  fastapi_voyager/voyager.py,sha256=nioo56oFDeZ8nwwPWDtaQbkpe4pVssFoBVHCWFhs0K4,13549
11
11
  fastapi_voyager/web/graph-ui.js,sha256=DTedkpZNbtufexONVkJ8mOwF_-VnvxoReYHtox6IKR4,5842
12
12
  fastapi_voyager/web/graphviz.svg.css,sha256=zDCjjpT0Idufu5YOiZI76PL70-avP3vTyzGPh9M85Do,1563
@@ -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.11.9.dist-info/METADATA,sha256=Lu6dgQqkJyfjVIO-NSzXKRdnq4HF30lD6_XXPqt51m8,10655
30
- fastapi_voyager-0.11.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
- fastapi_voyager-0.11.9.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
32
- fastapi_voyager-0.11.9.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
33
- fastapi_voyager-0.11.9.dist-info/RECORD,,
29
+ fastapi_voyager-0.11.11.dist-info/METADATA,sha256=uufha8zMMchzxEm6ZWW5r4VUF26sKl2DQ9G14HefXgw,11451
30
+ fastapi_voyager-0.11.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ fastapi_voyager-0.11.11.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
32
+ fastapi_voyager-0.11.11.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
33
+ fastapi_voyager-0.11.11.dist-info/RECORD,,