Skip to content

Commit 89dcf7b

Browse files
committed
Add interactive graph renderer
1 parent 530c875 commit 89dcf7b

23 files changed

Lines changed: 4517 additions & 18 deletions

docs/mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ nav:
1515
- Resource Management: resources.md
1616
- Interfaces: interfaces.md
1717
- Function Injection: function_injection.md
18+
- Interactive Graph: interactive_graph.md
1819
- Advanced Patterns:
1920
- Reusable Bundles: reusable_bundles.md
2021
- Conditional Registration: conditional_registration.md
@@ -31,6 +32,7 @@ nav:
3132
- Web Frameworks:
3233
- Django:
3334
- Django Integration: integrations/django/index.md
35+
- Interactive Graph: integrations/django/interactive_graph.md
3436
- Setup and Installation: integrations/django/setup.md
3537
- Inject in Views: integrations/django/view_injection.md
3638
- Request-Time Injection: integrations/django/request_time_injection.md

docs/pages/img/pet_store_demo.gif

14.8 MB
Loading

docs/pages/index.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@ and designed to fail fast: **if the container starts, it works**.
1212
</p>
1313
<p align="center"><i></i></p>
1414

15+
---
16+
17+
!!! interactive-graph "Interactive Graph"
18+
19+
Turn your container into an interactive dependency graph. Explore routes, functions, services, factories,
20+
configuration, and scopes in a live page with search, grouping, and dependency tracing.
21+
22+
Learn how it works and explore it on an demo pet store app:
23+
24+
[Documentation](interactive_graph.md){ .md-button target="_blank" }
25+
[:octicons-arrow-right-24: Live Demo](wireup_graph/pet_store.html){ .md-button .md-button--primary target="_blank" }
26+
27+
---
28+
1529
<div class="grid cards annotate index-cards" markdown>
1630

1731
- :material-shield-check:{ .lg .middle } __Correct by Default__

docs/pages/integrations/django/index.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ Wireup integrates with Django at both request scope and application scope. Use `
4646
`@inject_app` for non-request entry points, while keeping services as ordinary Python classes that are easy to test and
4747
reuse.
4848

49+
!!! interactive-graph "Interactive Graph"
50+
51+
Turn your container into an interactive dependency graph. Explore routes, functions, services, factories,
52+
configuration, and scopes in a live page with search, grouping, and dependency tracing.
53+
54+
Django can expose it with a small explicit view, and the same renderer is available for other apps too.
55+
56+
[Documentation](../../interactive_graph.md){ .md-button }
57+
[:octicons-arrow-right-24: Live Demo](../../wireup_graph/pet_store.html){ .md-button .md-button--primary target="_blank" }
58+
4959
## Quick Start
5060

5161
This is the shortest path to a working endpoint with explicit injection.
@@ -119,6 +129,7 @@ See [What Wireup Validates](../../what_wireup_validates.md) for the full rules.
119129
## Detailed Guides
120130

121131
- [Django Setup and Installation](setup.md): installation, middleware placement, and settings/config integration.
132+
- [Interactive Graph](interactive_graph.md): expose the graph page in Django and gate it by environment.
122133
- [Inject in Views](view_injection.md): core Django, DRF, Ninja, forms, and request-scoped patterns.
123134
- [Request-Time Injection](request_time_injection.md): reusable decorators, middleware entry points, and direct container access.
124135
- [App-Level Injection](app_injection.md): management commands, Django 6 background tasks, signals, checks, and scripts with `@inject_app`.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
description: Wireup interactive dependency graph for Django: expose the graph page, understand what it shows, and gate it by environment.
3+
---
4+
5+
## Enable The Interactive Graph
6+
7+
Create a small view that renders the graph page from the application container:
8+
9+
```python title="mysite/wireup_graph.py"
10+
from django.http import HttpRequest, HttpResponse
11+
from wireup.integration.django import get_app_container
12+
from wireup.renderer.full_page import GraphOptions, render_graph_page
13+
14+
15+
def wireup_graph(_request: HttpRequest) -> HttpResponse:
16+
return HttpResponse(
17+
render_graph_page(
18+
get_app_container(),
19+
title="My Django App - Wireup Graph",
20+
options=GraphOptions(base_module="mysite"),
21+
),
22+
content_type="text/html",
23+
)
24+
```
25+
26+
Then mount it in your URLconf:
27+
28+
```python title="mysite/urls.py"
29+
from django.conf import settings
30+
from django.urls import path
31+
32+
from mysite.wireup_graph import wireup_graph
33+
34+
urlpatterns = [
35+
# ...your existing routes...
36+
]
37+
38+
if settings.DEBUG:
39+
urlpatterns.append(path("_wireup", wireup_graph))
40+
```
41+
42+
Then open `http://127.0.0.1:8000/_wireup`.
43+
44+
## What It Shows
45+
46+
The graph can include:
47+
48+
- services and factories
49+
- configuration nodes
50+
- singleton, scoped, and transient lifetimes
51+
- discovered Django consumers that the graph can infer from the loaded app state
52+
53+
## Environment Gating
54+
55+
Because the graph exposes internal implementation details, it is best treated as a development tool.
56+
57+
A typical pattern is to mount the route only in local or non-production environments:
58+
59+
```python title="mysite/urls.py"
60+
if settings.DEBUG:
61+
urlpatterns.append(path("_wireup", wireup_graph))
62+
```
63+
64+
If you need stricter control, omit the route entirely in production or protect it like any other internal debug page.
65+
66+
## Related
67+
68+
- [Django Integration](index.md)
69+
- [General Interactive Graph Docs](../../interactive_graph.md)
70+
- [Django Request-Time Injection](request_time_injection.md)

docs/pages/integrations/fastapi/index.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ description: FastAPI dependency injection with Wireup: type-safe DI for routes,
3838

3939
</div>
4040

41-
!!! tip "Migrating from FastAPI Depends?"
41+
!!! interactive-graph "Interactive Graph"
4242

43-
Evaluating Wireup for your FastAPI project? Check out the migration page which includes common pain points with FastAPI Depends and how to solve them with Wireup as well
44-
as a low-friction migration path:
43+
Turn your container into an interactive dependency graph. Explore routes, functions, services, factories,
44+
configuration, and scopes in a live page with search, grouping, and dependency tracing.
4545

46-
[Migrate from FastAPI Depends to Wireup](../../migrate_to_wireup/fastapi_depends.md).
46+
47+
Learn how it works and explore it on an demo pet store app:
48+
49+
[Documentation](../../interactive_graph.md){ .md-button target="_blank" }
50+
[:octicons-arrow-right-24: Live Demo](../../wireup_graph/pet_store.html){ .md-button .md-button--primary target="_blank" }
4751

4852
## Quick Start
4953

@@ -103,6 +107,14 @@ See [What Wireup Validates](../../what_wireup_validates.md) for the full rules.
103107
- [FastAPI Testing](testing.md): `TestClient` lifespan usage, overrides, and request-lifecycle tests.
104108
- [Troubleshooting](troubleshooting.md): common setup/runtime errors and fast fixes.
105109

110+
!!! tip "Migrating from FastAPI Depends?"
111+
112+
Evaluating Wireup for your FastAPI project? Check out the migration page which includes common pain points with FastAPI Depends and how to solve them with Wireup as well
113+
as a low-friction migration path:
114+
115+
[Migrate from FastAPI Depends to Wireup](../../migrate_to_wireup/fastapi_depends.md).
116+
117+
106118
## API Reference
107119

108120
- [fastapi_integration](../../class/fastapi_integration.md)

docs/pages/integrations/flask/index.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ Dependency injection for Flask is available in the `wireup.integration.flask` mo
1818

1919
</div>
2020

21+
!!! interactive-graph "Interactive Graph"
22+
23+
Turn your container into an interactive dependency graph. Explore routes, functions, services, factories,
24+
configuration, and scopes in a live page with search, grouping, and dependency tracing.
25+
26+
Learn how it works and explore it on an demo pet store app:
27+
28+
[Documentation](../../interactive_graph.md){ .md-button target="_blank" }
29+
[:octicons-arrow-right-24: Live Demo](../../wireup_graph/pet_store.html){ .md-button .md-button--primary target="_blank" }
30+
2131
### Initialize the integration
2232

2333
First, [create a sync container](../../container.md) with your dependencies:
@@ -46,6 +56,16 @@ Then initialize the integration by calling `wireup.integration.flask.setup` afte
4656
wireup.integration.flask.setup(container, app)
4757
```
4858

59+
To expose the interactive dependency graph page, enable the graph endpoint during setup (defaults to `/_wireup`):
60+
61+
```python
62+
wireup.integration.flask.setup(
63+
container,
64+
app,
65+
add_graph_endpoint=True,
66+
)
67+
```
68+
4969
### Inject in Flask Views
5070

5171
To inject dependencies, add the type to the view's signature and annotate with `Injected[T]` or

docs/pages/interactive_graph.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Interactive Graph
2+
3+
!!! interactive-graph "Interactive Graph"
4+
5+
Turn your container into an interactive dependency graph. Explore routes, functions, services, factories,
6+
configuration, and scopes in a live page with search, grouping, and dependency tracing.
7+
8+
Learn how it works and explore it on an demo pet store app:
9+
10+
[:octicons-arrow-right-24: Live Demo](wireup_graph/pet_store.html){ .md-button .md-button--primary target="_blank" }
11+
12+
Wireup can render your dependency graph as an interactive page, including:
13+
14+
- routes and injected functions for selected frameworks
15+
- services and factories
16+
- configuration nodes
17+
- singleton, scoped, and transient lifetimes
18+
19+
This is one of the fastest ways to understand how a real application is wired together without relying on a static dump
20+
or a handwritten diagram.
21+
22+
## Preview
23+
24+
![Wireup interactive dependency graph demo](img/pet_store_demo.gif)
25+
26+
27+
## Automatic with FastAPI and Flask
28+
29+
FastAPI and Flask can expose the graph page automatically (defaults to `/_wireup`).
30+
31+
### FastAPI
32+
33+
```python
34+
import wireup.integration.fastapi
35+
36+
wireup.integration.fastapi.setup(
37+
container,
38+
app,
39+
add_graph_endpoint=True,
40+
)
41+
```
42+
43+
### Flask
44+
45+
```python
46+
import wireup.integration.flask
47+
48+
wireup.integration.flask.setup(
49+
container,
50+
app,
51+
add_graph_endpoint=True,
52+
)
53+
```
54+
55+
## Use in other frameworks
56+
57+
If your framework does not have automatic graph-page setup, you can still generate the graph yourself from Python.
58+
59+
### 1. Build graph data
60+
61+
```python
62+
from wireup.renderer.core import GraphOptions, to_graph_data
63+
64+
graph_data = to_graph_data(
65+
container, # or get_app_container() if the integration provides it
66+
options=GraphOptions(base_module="myapp"),
67+
)
68+
```
69+
70+
### 2. Render it as HTML
71+
72+
```python
73+
from wireup.renderer.full_page import full_page_renderer
74+
75+
html = full_page_renderer(graph_data, title="My App - Wireup Graph")
76+
```
77+
78+
### 3. Return it from a route
79+
80+
```python
81+
@app.get("/_wireup")
82+
def wireup_graph():
83+
graph_data = to_graph_data(
84+
container, options=GraphOptions(base_module="myapp")
85+
)
86+
html = full_page_renderer(graph_data, title="My App - Wireup Graph")
87+
88+
return HTMLResponse(html)
89+
```
90+
91+
92+
!!! tip
93+
Make sure to permission this endpoint appropriately in production since it exposes internal implementation details. You can disable it by omitting `add_graph_endpoint=True` or by not registering the route at all.

docs/pages/stylesheets/extra.css

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,25 @@ body[data-md-color-scheme="slate"] .grid.cards>ul>li {
2929

3030
.color-django {
3131
color: #0C4B33 !important;
32-
}
32+
}
33+
34+
:root {
35+
--md-admonition-icon--interactive-graph: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path d="M42.3 24l3.4-5.1a2 2 0 0 0 .2-1.7 1.8 1.8 0 0 0-1.2-1.2l-5.9-2.4-.5-5.9a2.1 2.1 0 0 0-.7-1.5 2 2 0 0 0-1.7-.3l-6.3 1.3-4.1-4.6a2.2 2.2 0 0 0-3 0l-4.1 4.6-6.3-1.3a2 2 0 0 0-1.7.3 2.1 2.1 0 0 0-.7 1.5l-.5 5.9L3.3 16a1.8 1.8 0 0 0-1.2 1.2 2 2 0 0 0 .2 1.7L5.7 24l-3.4 5.1a2 2 0 0 0 1 2.9l5.9 2.4.5 5.9a2.1 2.1 0 0 0 .7 1.5 2 2 0 0 0 1.7.3l6.3-1.3 4.1 4.5a2 2 0 0 0 3 0l4.1-4.5 6.3 1.3a2 2 0 0 0 1.7-.3 2.1 2.1 0 0 0 .7-1.5l.5-5.9 5.9-2.4a2 2 0 0 0 1-2.9ZM18 31.1l-4.2-3.2-1.1-.9h-.1l.6 1.4 1.7 4-2.1.8-3.5-8.6 2.1-.8 4.3 3.2 1.1.9h0a11.8 11.8 0 0 0-.6-1.3l-1.6-4.1 2.1-.9 3.5 8.6Zm3.3-1.3-3.5-8.7 6.6-2.6.7 1.8L20.7 22l.6 1.6L25.1 22l.7 1.7L22 25.2l.7 1.9 4.5-1.8.7 1.8Zm13.9-5.7-2.6-3.7-.9-1.5h-.1a14.7 14.7 0 0 1 .4 1.7l.8 4.5-2.1.9-5.9-7.7 2.2-.9 2.3 3.3 1.3 2h0a22.4 22.4 0 0 1-.4-2.3l-.7-4 2-.8L33.8 19 35 20.9h0s-.2-1.4-.4-2.4L34 14.6l2.1-.9 1.2 9.6Z"/></svg>');
36+
}
37+
38+
.md-typeset .admonition.interactive-graph,
39+
.md-typeset details.interactive-graph {
40+
border-color: #007acc;
41+
}
42+
43+
.md-typeset .interactive-graph > .admonition-title,
44+
.md-typeset .interactive-graph > summary {
45+
background-color: rgba(0, 122, 204, 0.12);
46+
}
47+
48+
.md-typeset .interactive-graph > .admonition-title::before,
49+
.md-typeset .interactive-graph > summary::before {
50+
background-color: #007acc;
51+
-webkit-mask-image: var(--md-admonition-icon--interactive-graph);
52+
mask-image: var(--md-admonition-icon--interactive-graph);
53+
}

0 commit comments

Comments
 (0)