djangomap 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 djangomap contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ prune docs
2
+ prune tests
3
+ exclude .gitignore
4
+ exclude CHANGELOG.md
@@ -0,0 +1,453 @@
1
+ Metadata-Version: 2.4
2
+ Name: djangomap
3
+ Version: 0.1.0
4
+ Summary: Turn any Django project into an interactive HTML architecture diagram: models, views, URLs, Celery tasks, signals — plus a health report.
5
+ Author-email: Armin <arminyarali1@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/selzman/djangomap
8
+ Project-URL: Repository, https://github.com/selzman/djangomap
9
+ Project-URL: Issues, https://github.com/selzman/djangomap/issues
10
+ Project-URL: Changelog, https://github.com/selzman/djangomap/blob/main/CHANGELOG.md
11
+ Keywords: django,diagram,visualization,architecture,erd,celery,static-analysis,ast,documentation,graph,code-quality,flowchart
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Framework :: Django
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Documentation
25
+ Classifier: Topic :: Software Development :: Documentation
26
+ Classifier: Topic :: Software Development :: Quality Assurance
27
+ Classifier: Topic :: Utilities
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.9
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENSE
32
+ Dynamic: license-file
33
+
34
+ <div align="center">
35
+
36
+ # djangomap
37
+
38
+ **Turn any Django project into a beautiful, interactive architecture diagram.**
39
+
40
+ Models · Views · URLs · Celery tasks · Beat schedules · Signals · Middleware · Admin · Serializers
41
+
42
+ <p>
43
+ <img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-7ee787.svg?style=flat-square">
44
+ <img alt="Python 3.9+" src="https://img.shields.io/badge/Python-3.9%2B-79c0ff.svg?style=flat-square&logo=python&logoColor=white">
45
+ <img alt="Django" src="https://img.shields.io/badge/Django-any%20version-092E20.svg?style=flat-square&logo=django&logoColor=white">
46
+ <img alt="Zero dependencies" src="https://img.shields.io/badge/dependencies-zero-d2a8ff.svg?style=flat-square">
47
+ </p>
48
+ <p>
49
+ <img alt="Output: single HTML file" src="https://img.shields.io/badge/output-single%20HTML%20file-ffa657.svg?style=flat-square&logo=html5&logoColor=white">
50
+ <img alt="Works offline" src="https://img.shields.io/badge/works-offline-56d4dd.svg?style=flat-square">
51
+ <img alt="Responsive" src="https://img.shields.io/badge/UI-responsive-ff9ecd.svg?style=flat-square">
52
+ <img alt="Static analysis: AST" src="https://img.shields.io/badge/analysis-AST%20only-f0c674.svg?style=flat-square">
53
+ <img alt="Health checks: 16" src="https://img.shields.io/badge/health%20checks-16-ff7b72.svg?style=flat-square">
54
+ </p>
55
+
56
+ [Why](#why) · [Quick start](#quick-start) · [The three tabs](#the-three-tabs) · [CLI](#cli-reference) · [CI](#ci-integration) · [How it works](#how-it-works) · [License](#license)
57
+
58
+ <img src="docs/images/apps-overview.png" alt="djangomap Apps view" width="100%">
59
+
60
+ </div>
61
+
62
+ ---
63
+
64
+ ## Why
65
+
66
+ You join a Django codebase with 40 apps. Which view serves `/checkout/`? What fires
67
+ `capture_payment`? Which models does the admin actually expose? Answering these means
68
+ grepping across dozens of files.
69
+
70
+ `djangomap` reads your project **without importing it** and produces a **single HTML
71
+ file** that answers those questions visually — plus it flags N+1 risks, circular app
72
+ dependencies and missing `related_name`s along the way.
73
+
74
+ | | |
75
+ |---|---|
76
+ | **Zero setup** | No database, no `DJANGO_SETTINGS_MODULE`, no installing the target project's dependencies |
77
+ | **Zero dependencies** | Pure Python standard library — `ast` and nothing else |
78
+ | **Fully offline** | Tailwind is pre-compiled and inlined; the page makes no network requests |
79
+ | **One file** | Email it, commit it, attach it to a PR, open it from disk |
80
+ | **Responsive** | Works on desktop, tablet and phone |
81
+
82
+ ---
83
+
84
+ ## Quick start
85
+
86
+ ```bash
87
+ pip install -e ./djangomap
88
+ djangomap /path/to/your/project -o diagram.html
89
+ open diagram.html
90
+ ```
91
+
92
+ That's it. For the full experience, add source links:
93
+
94
+ ```bash
95
+ djangomap . \
96
+ --title "My Shop" \
97
+ --editor vscode \
98
+ --repo-url https://github.com/me/myshop \
99
+ --branch main \
100
+ -o diagram.html
101
+ ```
102
+
103
+ Or use it as a library:
104
+
105
+ ```python
106
+ from djangomap import scan_project, render_html
107
+ from djangomap.analysis import analyse
108
+
109
+ proj = scan_project("/path/to/project")
110
+ data = proj.to_dict()
111
+ data["health"] = analyse(proj)
112
+
113
+ render_html(data, "diagram.html")
114
+ print(proj.stats()) # {'model': 8, 'view': 8, 'url': 12, ...}
115
+ ```
116
+
117
+ ---
118
+
119
+ ## The three tabs
120
+
121
+ ### 1 · Apps — what is in each app
122
+
123
+ Every app becomes its own board with a dedicated colour. Inside, cards are grouped by
124
+ kind and show a useful summary line: a model's field count, a URL's handler and
125
+ `name=`, a view's base class, a task's argument signature, a beat entry's schedule.
126
+
127
+ Relationship wires are routed **through the gutters between boards**, so they never
128
+ cut across cards — including relations that span apps.
129
+
130
+ <img src="docs/images/apps-overview.png" alt="Apps overview" width="100%">
131
+
132
+ **Click any card** to open the detail panel: full field list with `on_delete` and
133
+ `related_name`, the `Meta` class, properties, methods, cyclomatic complexity, detected
134
+ issues, and every relation as a clickable link so you can walk the graph.
135
+
136
+ <img src="docs/images/detail-panel.png" alt="Detail panel" width="100%">
137
+
138
+ Selecting a node also **dims everything unrelated**, leaving just its neighbourhood lit:
139
+
140
+ <img src="docs/images/focus-mode.png" alt="Focus mode" width="100%">
141
+
142
+ > Drag a board header to rearrange · scroll to zoom · `F` to fit · `Esc` to clear
143
+ > · collapse individual boards or all at once for a bird's-eye view
144
+
145
+ ---
146
+
147
+ ### 2 · Flow — how the system fits together
148
+
149
+ Four architecture views, switchable from the toolbar.
150
+
151
+ #### Request Lifecycle
152
+
153
+ The full path of an HTTP request through parallel lanes: Middleware → URLconf → View
154
+ → Serializer/Form → Model, with a separate lane for async Celery work.
155
+
156
+ <img src="docs/images/flow-request.png" alt="Request lifecycle" width="100%">
157
+
158
+ #### App Dependencies
159
+
160
+ Which apps import which, derived from real `import` statements, annotated with
161
+ reference counts. Circular dependencies show up immediately.
162
+
163
+ <img src="docs/images/flow-appdeps.png" alt="App dependencies" width="100%">
164
+
165
+ #### Celery Pipeline
166
+
167
+ Producers (views, signals, beat entries, management commands) → Broker → Workers →
168
+ Result backend, including task-to-task chains.
169
+
170
+ <img src="docs/images/flow-celery.png" alt="Celery pipeline" width="100%">
171
+
172
+ #### Data Model
173
+
174
+ A full ERD: every model with its fields, and the FK / M2M / O2O relations between
175
+ them, grouped by app.
176
+
177
+ <img src="docs/images/flow-erd.png" alt="ERD" width="100%">
178
+
179
+ ---
180
+
181
+ ### 3 · Health — what is wrong
182
+
183
+ A 0–100 score plus issues grouped by check. **Click any issue to jump straight to that
184
+ card** in the Apps tab. Cards with problems get a coloured dot.
185
+
186
+ <img src="docs/images/health.png" alt="Health tab" width="100%">
187
+
188
+ Below the issue list, a per-app breakdown shows where the debt is concentrated:
189
+
190
+ <img src="docs/images/health-perapp.png" alt="Per-app health" width="100%">
191
+
192
+ #### Checks
193
+
194
+ | Check | Severity | Meaning |
195
+ |---|---|---|
196
+ | `view.n_plus_one` | 🔴 error | Model has FKs but the view never calls `select_related`/`prefetch_related` |
197
+ | `url.no_view` | 🔴 error | URL is not wired to any known view |
198
+ | `app.cycle` | 🔴 error | Circular dependency between apps |
199
+ | `complexity.high` | 🟡 warn | Cyclomatic complexity ≥ 10 (error at ≥ 18) |
200
+ | `model.no_str` | 🟡 warn | Model has no `__str__`, so it renders as `Object (1)` in admin |
201
+ | `model.no_ordering` | 🟡 warn | Used in a `ListView` but has no `Meta.ordering` → unstable pagination |
202
+ | `url.no_name` | 🟡 warn | No `name=`, so it cannot be used with `reverse()` |
203
+ | `view.no_perm` | 🟡 warn | DRF view without `permission_classes` |
204
+ | `task.orphan` | 🟡 warn | Task is never called — no `delay()` and no beat schedule |
205
+ | `signal.no_sender` | 🟡 warn | `@receiver` without `sender` fires for *every* model |
206
+ | `model.fk_no_related` | 🔵 info | `ForeignKey` without `related_name` |
207
+ | `model.orphan` | 🔵 info | No view / serializer / admin references this model |
208
+ | `model.no_indexes` | 🔵 info | Many fields but no `db_index` anywhere |
209
+ | `task.no_retry` | 🔵 info | No `max_retries` / `autoretry_for` |
210
+ | `task.no_bind_retry` | 🔵 info | Uses `self.retry` but not declared with `bind=True` |
211
+ | `view.unauth` | 🔵 info | No `login_required` / permission mixin |
212
+
213
+ > `view.unauth` and `model.orphan` are heuristic and can be noisy on real projects,
214
+ > which is why they are `info` and barely affect the score.
215
+
216
+ ---
217
+
218
+ ## Responsive
219
+
220
+ The whole UI adapts down to a 320px phone.
221
+
222
+ <div align="center">
223
+ <img src="docs/images/mobile-apps.png" alt="Mobile" width="30%">
224
+ <img src="docs/images/mobile-drawer.png" alt="Mobile drawer" width="30%">
225
+ <img src="docs/images/mobile-sheet.png" alt="Mobile detail sheet" width="30%">
226
+ </div>
227
+
228
+ | Breakpoint | Behaviour |
229
+ |---|---|
230
+ | ≥ 1536px | Kind chips inline in the header |
231
+ | < 1536px | Kind filters move into the drawer via the **Kinds** button |
232
+ | ≥ 1024px | Sidebar always visible |
233
+ | < 1024px | Sidebar becomes an off-canvas drawer behind ☰ ; detail panel becomes a bottom sheet and diagrams auto-fit above it |
234
+ | < 760px | Flow layers stack vertically and fit to width |
235
+
236
+ Pinch-to-zoom and touch panning work on both canvases. Tablet reflows to two columns:
237
+
238
+ <img src="docs/images/tablet-apps.png" alt="Tablet" width="100%">
239
+
240
+ ---
241
+
242
+ ## CLI reference
243
+
244
+ ```
245
+ djangomap [path] [options]
246
+ ```
247
+
248
+ | Option | Description |
249
+ |---|---|
250
+ | `path` | Project root (default: `.`) |
251
+ | `-o, --out FILE` | Output HTML file (default: `djangomap.html`) |
252
+ | `--title TEXT` | Diagram title |
253
+ | `--json FILE` | Also dump the raw graph as JSON |
254
+ | `--editor NAME` | `vscode` · `vscode-insiders` · `pycharm` · `none` |
255
+ | `--repo-url URL` | e.g. `https://github.com/me/proj` — enables "view on remote" links |
256
+ | `--branch NAME` | Branch for `--repo-url` (default: `main`) |
257
+ | `--format FMT` | Print a text diagram: `mermaid-erd` · `mermaid-flow` · `dot` |
258
+ | `--markdown FILE` | Write a Markdown report with an embedded Mermaid ERD |
259
+ | `--fail-on LEVEL` | Exit 1 if issues at `error` / `warn` / `info` exist |
260
+ | `--no-health` | Skip the health analysis |
261
+
262
+ ### Text exports
263
+
264
+ Paste straight into a README or PR comment:
265
+
266
+ ```bash
267
+ djangomap . --format mermaid-erd # GitHub renders this natively
268
+ djangomap . --format mermaid-flow
269
+ djangomap . --format dot | dot -Tsvg -o graph.svg
270
+ djangomap . --markdown report.md
271
+ ```
272
+
273
+ <details>
274
+ <summary><b>Example Mermaid output</b></summary>
275
+
276
+ ```
277
+ erDiagram
278
+ Product {
279
+ Char title
280
+ Decimal price
281
+ ForeignKey category FK
282
+ ManyToMany tags FK
283
+ }
284
+ Product ||--o{ Category : "category"
285
+ Product }o--o{ Tag : "tags"
286
+ ```
287
+ </details>
288
+
289
+ ---
290
+
291
+ ## CI integration
292
+
293
+ Fail the build when architectural errors appear:
294
+
295
+ ```yaml
296
+ # .github/workflows/architecture.yml
297
+ name: Architecture
298
+ on: [push, pull_request]
299
+
300
+ jobs:
301
+ djangomap:
302
+ runs-on: ubuntu-latest
303
+ steps:
304
+ - uses: actions/checkout@v4
305
+ - uses: actions/setup-python@v5
306
+ with: { python-version: "3.12" }
307
+ - run: pip install -e ./djangomap
308
+ - run: djangomap . --fail-on error -o diagram.html
309
+ - uses: actions/upload-artifact@v4
310
+ if: always()
311
+ with:
312
+ name: architecture-diagram
313
+ path: diagram.html
314
+ ```
315
+
316
+ Every PR then carries a downloadable, up-to-date diagram of the codebase.
317
+
318
+ ---
319
+
320
+ ## Keyboard shortcuts & permalinks
321
+
322
+ | Key | Action |
323
+ |---|---|
324
+ | `1` `2` `3` | Switch to Apps / Flow / Health |
325
+ | `F` | Fit the current view |
326
+ | `Esc` | Clear the selection |
327
+
328
+ The active tab, flow view, selected node and every filter are encoded in the URL
329
+ `#hash`. Send the link to a teammate and they land on exactly the same view.
330
+
331
+ ---
332
+
333
+ ## What gets extracted
334
+
335
+ <details open>
336
+ <summary><b>Models</b></summary>
337
+
338
+ Every field with its type, `max_length`, `null` / `blank` / `unique` / `db_index` /
339
+ `primary_key`, `on_delete`, `related_name`, `default`, `help_text`, whether it has
340
+ `choices` — plus the `Meta` class, `@property` methods, custom managers and
341
+ cyclomatic complexity.
342
+ </details>
343
+
344
+ <details>
345
+ <summary><b>Views</b></summary>
346
+
347
+ CBV and FBV, HTTP methods (from `get`/`post` methods or `@api_view`), `model`,
348
+ `queryset`, `serializer_class`, `form_class`, `template_name`, `permission_classes`,
349
+ `authentication_classes`, `paginate_by`, `lookup_field`, `filter_backends`, and the
350
+ list of URLs that reach the view.
351
+ </details>
352
+
353
+ <details>
354
+ <summary><b>URLs</b></summary>
355
+
356
+ `path()` / `re_path()` / `url()` / `include()`, path converters like `<int:pk>`,
357
+ `name=`, extra kwargs, and DRF router `register()` calls.
358
+ </details>
359
+
360
+ <details>
361
+ <summary><b>Celery</b></summary>
362
+
363
+ `@shared_task`, `@app.task` and method-level tasks with their full argument
364
+ signature and options (`bind`, `max_retries`, `queue`, `rate_limit`, `autoretry_for`,
365
+ `acks_late`, `time_limit`, …), the `delay()` / `apply_async()` call chain, and every
366
+ `CELERY_BEAT_SCHEDULE` entry wired to its task.
367
+ </details>
368
+
369
+ <details>
370
+ <summary><b>Everything else</b></summary>
371
+
372
+ Signals (type + `sender`), middleware, management commands, forms, serializers
373
+ (`Meta.model`, `fields`, `read_only_fields`), admin classes (`list_display`,
374
+ `list_filter`, `search_fields`, registrations), and settings: `INSTALLED_APPS`,
375
+ `MIDDLEWARE`, `AUTH_USER_MODEL`, `ROOT_URLCONF`, broker and result backend.
376
+ </details>
377
+
378
+ ### Relationship types
379
+
380
+ | Wire | Meaning |
381
+ |---|---|
382
+ | `fk` `m2m` `o2o` | Model relations |
383
+ | `routes` | URL → View |
384
+ | `calls` | `task.delay()` / `apply_async()` |
385
+ | `schedules` | Beat entry → task |
386
+ | `uses` | View → serializer / form / model |
387
+ | `queries` | ORM access inside a view or task |
388
+ | `manages` | Admin class → model |
389
+ | `listens` | Signal receiver → sender model |
390
+ | `inherits` | Class inheritance within the project |
391
+
392
+ ---
393
+
394
+ ## How it works
395
+
396
+ ```
397
+ scanner.py walks the tree, parses each .py with ast, emits nodes + edges
398
+ analysis.py runs 16 checks over that graph, scores the project
399
+ export.py renders Mermaid / DOT / Markdown
400
+ render.py inlines the graph JSON + pre-built Tailwind into one HTML file
401
+ cli.py argument parsing and orchestration
402
+ ```
403
+
404
+ Because everything is AST-based, **your code is never executed** — safe to point at
405
+ an unfamiliar repository. The trade-off is that dynamically constructed URLconfs or
406
+ programmatically generated models won't be seen. For those, the graph is a very good
407
+ approximation rather than a perfect runtime reflection.
408
+
409
+ Migrations, `node_modules`, virtualenvs, caches and static dirs are skipped.
410
+
411
+ ---
412
+
413
+ ## Development
414
+
415
+ ```bash
416
+ python -m djangomap.cli ./sample_shop -o demo.html # run against the bundled sample
417
+ ```
418
+
419
+ The Tailwind stylesheet is pre-built at `djangomap/tailwind.css`. Rebuild it after
420
+ editing `template.html`:
421
+
422
+ ```bash
423
+ npx tailwindcss -c tailwind.config.js -i tw.css -o djangomap/tailwind.css --minify
424
+ ```
425
+
426
+ The repo ships a `sample_shop/` Django project (4 apps, 8 models, 6 tasks, DRF,
427
+ Celery Beat, a management command) used for the screenshots above.
428
+
429
+ ---
430
+
431
+ ## Limitations
432
+
433
+ - Dynamic URLconfs and runtime-generated models are invisible to static analysis
434
+ - Third-party apps are only mapped if they live inside the scanned tree
435
+ - `related_name` reverse accessors that Django creates implicitly are not inferred
436
+ - The N+1 check is a heuristic: it flags missing `select_related` but cannot know
437
+ whether the template actually traverses the relation
438
+
439
+ ---
440
+
441
+ ## License
442
+
443
+ Released under the [MIT License](LICENSE) — free for personal and commercial use.
444
+
445
+ ```
446
+ Copyright (c) 2026 djangomap contributors
447
+ ```
448
+
449
+ ---
450
+
451
+ <div align="center">
452
+ <sub>Built with Python's <code>ast</code>, Tailwind CSS and hand-rolled SVG. No runtime dependencies.</sub>
453
+ </div>