codezoom 0.1.0.dev0__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.
@@ -0,0 +1,549 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>codezoom</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.28.1/cytoscape.min.js"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/dagre/0.8.5/dagre.min.js"></script>
9
+ <script src="https://unpkg.com/cytoscape-dagre@2.2.2/cytoscape-dagre.js"></script>
10
+ <style>
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ box-sizing: border-box;
15
+ }
16
+
17
+ body {
18
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
19
+ background: #f5f5f5;
20
+ }
21
+
22
+ #header {
23
+ background: white;
24
+ padding: 20px;
25
+ border-bottom: 1px solid #ddd;
26
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
27
+ }
28
+
29
+ #header h1 {
30
+ font-size: 24px;
31
+ margin-bottom: 10px;
32
+ }
33
+
34
+ #header p {
35
+ color: #666;
36
+ font-size: 14px;
37
+ }
38
+
39
+ #controls {
40
+ padding: 15px;
41
+ background: white;
42
+ border-bottom: 1px solid #ddd;
43
+ display: flex;
44
+ gap: 10px;
45
+ flex-wrap: wrap;
46
+ align-items: center;
47
+ }
48
+
49
+ button {
50
+ padding: 8px 16px;
51
+ background: #2c3e50;
52
+ color: white;
53
+ border: none;
54
+ border-radius: 4px;
55
+ cursor: pointer;
56
+ font-size: 14px;
57
+ }
58
+
59
+ button:hover {
60
+ background: #34495e;
61
+ }
62
+
63
+ button:disabled {
64
+ background: #bdc3c7;
65
+ cursor: not-allowed;
66
+ }
67
+
68
+ #breadcrumb {
69
+ flex: 1;
70
+ font-size: 14px;
71
+ color: #666;
72
+ font-style: italic;
73
+ }
74
+
75
+ #breadcrumb a {
76
+ color: #2c3e50;
77
+ cursor: pointer;
78
+ text-decoration: underline;
79
+ margin: 0 5px;
80
+ }
81
+
82
+ #breadcrumb a:hover {
83
+ color: #34495e;
84
+ }
85
+
86
+ #cy {
87
+ width: 100%;
88
+ height: calc(100vh - 200px);
89
+ background: white;
90
+ border-top: 1px solid #ddd;
91
+ }
92
+
93
+ #info {
94
+ padding: 10px 15px;
95
+ background: #e8f4f8;
96
+ border-left: 4px solid #3498db;
97
+ font-size: 13px;
98
+ color: #333;
99
+ }
100
+ </style>
101
+ </head>
102
+ <body>
103
+ <div id="header">
104
+ <h1 id="titleText"></h1>
105
+ <p>Click on any node to zoom into its dependencies. Use breadcrumbs to navigate back.</p>
106
+ </div>
107
+
108
+ <div id="info">
109
+ <strong>How to use:</strong> Click on a package name to drill down and see its internal structure and dependencies. Use the breadcrumb navigation at the top to go back up levels.
110
+ </div>
111
+
112
+ <div id="controls">
113
+ <button id="backBtn" onclick="goBack()">&#8592; Back</button>
114
+ <button id="resetBtn" onclick="reset()">Reset to Top</button>
115
+ <button onclick="applyLayout('dagre', 'cose')">Layout: Hierarchical</button>
116
+ <button onclick="applyLayout('cose')">Layout: Force-Directed</button>
117
+ <button onclick="cy.fit()">Fit View</button>
118
+ <div style="flex: 1; display: flex; align-items: center; gap: 20px; margin-left: 20px;">
119
+ <div style="display: flex; align-items: center; gap: 10px;">
120
+ <label for="sizeSlider" style="color: #666; font-size: 14px;">Node Size:</label>
121
+ <input type="range" id="sizeSlider" min="20" max="100" value="50" style="width: 120px;">
122
+ <span id="sizeValue" style="color: #666; font-size: 14px; min-width: 30px;">50</span>
123
+ </div>
124
+ <div style="display: flex; align-items: center; gap: 10px;">
125
+ <label for="fontSlider" style="color: #666; font-size: 14px;">Font Size:</label>
126
+ <input type="range" id="fontSlider" min="8" max="40" value="12" style="width: 120px;">
127
+ <span id="fontValue" style="color: #666; font-size: 14px; min-width: 30px;">12</span>
128
+ </div>
129
+ </div>
130
+ <div id="breadcrumb"></div>
131
+ </div>
132
+
133
+ <div id="cy"></div>
134
+
135
+ <script>
136
+ // All data injected as a single JSON blob
137
+ const data = $DATA_JSON;
138
+
139
+ const hierarchy = data.hierarchy;
140
+ const functionData = data.functionData;
141
+ const pythonDeps = data.external_deps;
142
+ const pythonDepsDirect = data.external_deps_direct;
143
+ const pythonDepsGraph = data.external_deps_graph;
144
+ const ROOT = data.root_node_id;
145
+
146
+ // Set page title
147
+ document.getElementById('titleText').textContent = data.project_name + ' Dependency Explorer';
148
+ document.title = data.project_name + ' — codezoom';
149
+
150
+ // Navigation state
151
+ let currentNode = ROOT;
152
+ const history = [ROOT];
153
+
154
+ let cy = null;
155
+
156
+ function applyNodeColors() {
157
+ if (!cy) return;
158
+ cy.nodes().forEach(node => {
159
+ const d = node.data();
160
+ if (d.bgColor) node.style('background-color', d.bgColor);
161
+ if (d.borderWidth) node.style('border-width', d.borderWidth);
162
+ if (d.borderColor) node.style('border-color', d.borderColor);
163
+ });
164
+ }
165
+
166
+ function initCytoscape() {
167
+ if (cy) cy.destroy();
168
+
169
+ cy = cytoscape({
170
+ container: document.getElementById('cy'),
171
+ elements: buildGraphData(currentNode),
172
+ style: [
173
+ {
174
+ selector: 'node',
175
+ style: {
176
+ 'content': 'data(label)',
177
+ 'width': 50,
178
+ 'height': 50,
179
+ 'padding': '5px',
180
+ 'text-opacity': 1,
181
+ 'color': '#222222',
182
+ 'font-size': '12px',
183
+ 'font-weight': 'bold',
184
+ 'text-valign': 'center',
185
+ 'text-halign': 'center',
186
+ 'background-color': '#3498db',
187
+ 'border-width': 2,
188
+ 'border-color': '#2980b9',
189
+ 'background-opacity': 0.9,
190
+ }
191
+ },
192
+ {
193
+ selector: 'edge',
194
+ style: {
195
+ 'curve-style': 'bezier',
196
+ 'target-arrow-shape': 'triangle',
197
+ 'target-arrow-color': '#666',
198
+ 'target-arrow-fill': 'filled',
199
+ 'arrow-scale': 1.5,
200
+ 'line-color': '#95a5a6',
201
+ 'width': 2,
202
+ 'opacity': 0.7,
203
+ }
204
+ },
205
+ {
206
+ selector: 'node:hover',
207
+ style: {
208
+ 'background-color': '#f1c40f',
209
+ 'border-color': '#d68910',
210
+ }
211
+ },
212
+ ],
213
+ layout: {
214
+ name: 'cose',
215
+ directed: true,
216
+ animate: true,
217
+ animationDuration: 500,
218
+ },
219
+ wheelSensitivity: 0.1,
220
+ minZoom: 0.1,
221
+ maxZoom: 3,
222
+ });
223
+
224
+ cy.on('tap', 'node', function(evt) {
225
+ const node = evt.target;
226
+ const nodeId = node.id();
227
+
228
+ const hasChildren = hierarchy[nodeId] && hierarchy[nodeId].children && hierarchy[nodeId].children.length > 0;
229
+ const hasFunctions = functionData[nodeId] && Object.keys(functionData[nodeId]).length > 0;
230
+
231
+ let isClickableClass = false;
232
+ if (nodeId.includes(':')) {
233
+ const lastColonIdx = nodeId.lastIndexOf(':');
234
+ const moduleId = nodeId.substring(0, lastColonIdx);
235
+ const classPath = nodeId.substring(lastColonIdx + 1);
236
+ const isMethodNode = classPath.includes('.');
237
+ if (!isMethodNode) {
238
+ const className = classPath;
239
+ if (functionData[moduleId] && functionData[moduleId][className]) {
240
+ const classInfo = functionData[moduleId][className];
241
+ isClickableClass = classInfo.type === 'class' && classInfo.methods && Object.keys(classInfo.methods).length > 0;
242
+ }
243
+ }
244
+ }
245
+
246
+ if (hasChildren || hasFunctions || isClickableClass) {
247
+ drillInto(nodeId);
248
+ }
249
+ });
250
+
251
+ setTimeout(() => {
252
+ applyNodeColors();
253
+ cy.fit();
254
+ }, 100);
255
+ }
256
+
257
+ function buildGraphData(nodeId) {
258
+ const elements = [];
259
+
260
+ // Method-level nodes (format: "moduleId:className")
261
+ if (nodeId.includes(':')) {
262
+ const lastColonIdx = nodeId.lastIndexOf(':');
263
+ const moduleId = nodeId.substring(0, lastColonIdx);
264
+ const classPath = nodeId.substring(lastColonIdx + 1);
265
+ const className = classPath.split('.')[0];
266
+
267
+ if (functionData[moduleId] && functionData[moduleId][className] && functionData[moduleId][className].methods) {
268
+ return buildMethodGraph(moduleId, className);
269
+ }
270
+ }
271
+
272
+ // Top-level: show external dependencies
273
+ if (nodeId === ROOT && history.length === 1 && pythonDeps.length > 0) {
274
+ const seenEdges = new Set();
275
+
276
+ pythonDeps.forEach(dep => {
277
+ const isDirect = pythonDepsDirect.includes(dep);
278
+ elements.push({
279
+ data: {
280
+ id: 'py-dep-' + dep,
281
+ label: dep,
282
+ bgColor: isDirect ? '#34495e' : '#95a5a6',
283
+ borderWidth: isDirect ? 2 : 1,
284
+ borderColor: isDirect ? '#2c3e50' : '#7f8c8d',
285
+ }
286
+ });
287
+ });
288
+
289
+ pythonDepsDirect.forEach(dep => {
290
+ const edgeId = ROOT + '->py-dep-' + dep;
291
+ if (!seenEdges.has(edgeId)) {
292
+ elements.push({ data: { id: edgeId, source: ROOT, target: 'py-dep-' + dep } });
293
+ seenEdges.add(edgeId);
294
+ }
295
+ });
296
+
297
+ pythonDeps.forEach(dep => {
298
+ if (pythonDepsGraph[dep]) {
299
+ pythonDepsGraph[dep].forEach(depDep => {
300
+ if (pythonDeps.includes(depDep)) {
301
+ const edgeId = 'py-dep-' + dep + '->py-dep-' + depDep;
302
+ if (!seenEdges.has(edgeId)) {
303
+ elements.push({ data: { id: edgeId, source: 'py-dep-' + dep, target: 'py-dep-' + depDep } });
304
+ seenEdges.add(edgeId);
305
+ }
306
+ }
307
+ });
308
+ }
309
+ });
310
+
311
+ // Root node (drillable)
312
+ elements.push({
313
+ data: {
314
+ id: ROOT,
315
+ label: data.project_name,
316
+ bgColor: '#e74c3c',
317
+ borderWidth: 3,
318
+ borderColor: '#c0392b',
319
+ }
320
+ });
321
+
322
+ return elements;
323
+ }
324
+
325
+ // Regular hierarchy node
326
+ const node = hierarchy[nodeId];
327
+ if (!node) return elements;
328
+
329
+ // Leaf module with function data
330
+ if (functionData[nodeId]) {
331
+ return buildFunctionGraph(nodeId);
332
+ }
333
+
334
+ const children = node.children || [];
335
+ const childSet = new Set(children);
336
+
337
+ if (children.length > 0) {
338
+ children.forEach(childId => {
339
+ const childNode = hierarchy[childId];
340
+ const hasChildren = childNode && childNode.children && childNode.children.length > 0;
341
+ const hasFunctions = functionData[childId];
342
+ const isClickable = hasChildren || hasFunctions;
343
+
344
+ elements.push({
345
+ data: {
346
+ id: childId,
347
+ label: childId.split('.').pop(),
348
+ bgColor: isClickable ? '#f39c12' : '#3498db',
349
+ borderWidth: isClickable ? 3 : 2,
350
+ borderColor: isClickable ? '#d68910' : '#2980b9',
351
+ }
352
+ });
353
+ });
354
+
355
+ children.forEach(childId => {
356
+ const childNode = hierarchy[childId];
357
+ if (childNode && childNode.imports_to) {
358
+ childNode.imports_to.forEach(targetId => {
359
+ if (childSet.has(targetId) && childId !== targetId) {
360
+ const edgeId = childId + '->' + targetId;
361
+ if (!elements.find(el => el.data.id === edgeId)) {
362
+ elements.push({ data: { id: edgeId, source: childId, target: targetId } });
363
+ }
364
+ }
365
+ });
366
+ }
367
+ });
368
+ }
369
+
370
+ return elements;
371
+ }
372
+
373
+ function buildFunctionGraph(moduleId) {
374
+ const elements = [];
375
+ const functions = functionData[moduleId];
376
+ if (!functions) return elements;
377
+
378
+ Object.entries(functions).forEach(([name, info]) => {
379
+ const hasMethodsOrCalls = (info.methods && Object.keys(info.methods).length > 0) || (info.calls && info.calls.length > 0);
380
+ let bgColor = info.type === 'class' ? '#9b59b6' : '#16a085';
381
+ let borderWidth = hasMethodsOrCalls ? 3 : 2;
382
+
383
+ elements.push({
384
+ data: {
385
+ id: moduleId + ':' + name,
386
+ label: name,
387
+ bgColor: bgColor,
388
+ borderWidth: borderWidth,
389
+ borderColor: info.type === 'class' ? '#8e44ad' : '#117a65',
390
+ hasChildren: info.type === 'class' && info.methods && Object.keys(info.methods).length > 0,
391
+ }
392
+ });
393
+ });
394
+
395
+ Object.entries(functions).forEach(([name, info]) => {
396
+ if (info.calls && info.calls.length > 0) {
397
+ info.calls.forEach(calledName => {
398
+ if (functions[calledName]) {
399
+ const edgeId = moduleId + ':' + name + '->' + calledName;
400
+ if (!elements.find(el => el.data.id === edgeId)) {
401
+ elements.push({ data: { id: edgeId, source: moduleId + ':' + name, target: moduleId + ':' + calledName } });
402
+ }
403
+ }
404
+ });
405
+ }
406
+
407
+ if (info.inherits && info.inherits.length > 0) {
408
+ info.inherits.forEach(parentName => {
409
+ if (functions[parentName]) {
410
+ const edgeId = moduleId + ':' + name + '-inherits-' + parentName;
411
+ if (!elements.find(el => el.data.id === edgeId)) {
412
+ elements.push({ data: { id: edgeId, source: moduleId + ':' + name, target: moduleId + ':' + parentName } });
413
+ }
414
+ }
415
+ });
416
+ }
417
+ });
418
+
419
+ return elements;
420
+ }
421
+
422
+ function buildMethodGraph(moduleId, className) {
423
+ const elements = [];
424
+ const functions = functionData[moduleId];
425
+ if (!functions || !functions[className]) return elements;
426
+
427
+ const classInfo = functions[className];
428
+ const methods = classInfo.methods || {};
429
+
430
+ Object.entries(methods).forEach(([methodName, methodInfo]) => {
431
+ elements.push({
432
+ data: {
433
+ id: moduleId + ':' + className + '.' + methodName,
434
+ label: methodName,
435
+ bgColor: '#e74c3c',
436
+ borderWidth: 2,
437
+ borderColor: '#c0392b',
438
+ }
439
+ });
440
+ });
441
+
442
+ Object.entries(methods).forEach(([methodName, methodInfo]) => {
443
+ if (methodInfo.calls && methodInfo.calls.length > 0) {
444
+ methodInfo.calls.forEach(calledName => {
445
+ if (methods[calledName]) {
446
+ const edgeId = moduleId + ':' + className + '.' + methodName + '->' + calledName;
447
+ if (!elements.find(el => el.data.id === edgeId)) {
448
+ elements.push({ data: { id: edgeId, source: moduleId + ':' + className + '.' + methodName, target: moduleId + ':' + className + '.' + calledName } });
449
+ }
450
+ }
451
+ });
452
+ }
453
+ });
454
+
455
+ return elements;
456
+ }
457
+
458
+ function drillInto(nodeId) {
459
+ if (!nodeId.includes(':') && !hierarchy[nodeId]) return;
460
+ currentNode = nodeId;
461
+ history.push(nodeId);
462
+ updateUI();
463
+ }
464
+
465
+ function goBack() {
466
+ if (history.length > 1) {
467
+ history.pop();
468
+ currentNode = history[history.length - 1];
469
+ updateUI();
470
+ }
471
+ }
472
+
473
+ function reset() {
474
+ currentNode = ROOT;
475
+ history.length = 1;
476
+ history[0] = ROOT;
477
+ updateUI();
478
+ }
479
+
480
+ function updateUI() {
481
+ updateBreadcrumb();
482
+ updateBackButton();
483
+ initCytoscape();
484
+ }
485
+
486
+ function updateBreadcrumb() {
487
+ const breadcrumb = document.getElementById('breadcrumb');
488
+ const parts = [];
489
+
490
+ history.forEach((nodeId, idx) => {
491
+ const label = idx === 0 ? data.project_name : nodeId;
492
+ if (idx === history.length - 1) {
493
+ parts.push('<strong>' + label + '</strong>');
494
+ } else {
495
+ parts.push('<a onclick="jumpTo(' + idx + ')">' + label + '</a>');
496
+ }
497
+ });
498
+
499
+ breadcrumb.innerHTML = '<strong>Navigation:</strong> ' + parts.join(' / ');
500
+ }
501
+
502
+ function jumpTo(idx) {
503
+ history.length = idx + 1;
504
+ currentNode = history[history.length - 1];
505
+ updateUI();
506
+ }
507
+
508
+ function updateBackButton() {
509
+ document.getElementById('backBtn').disabled = history.length <= 1;
510
+ }
511
+
512
+ function applyLayout(name, fallback) {
513
+ try {
514
+ cy.layout({name: name}).run();
515
+ } catch(e) {
516
+ if (fallback) cy.layout({name: fallback}).run();
517
+ }
518
+ }
519
+
520
+ // Node size slider
521
+ const sizeSlider = document.getElementById('sizeSlider');
522
+ const sizeValue = document.getElementById('sizeValue');
523
+
524
+ sizeSlider.addEventListener('input', function() {
525
+ const newSize = this.value;
526
+ sizeValue.textContent = newSize;
527
+ if (cy) {
528
+ cy.nodes().style('width', newSize);
529
+ cy.nodes().style('height', newSize);
530
+ }
531
+ });
532
+
533
+ // Font size slider
534
+ const fontSlider = document.getElementById('fontSlider');
535
+ const fontValue = document.getElementById('fontValue');
536
+
537
+ fontSlider.addEventListener('input', function() {
538
+ const newFontSize = this.value;
539
+ fontValue.textContent = newFontSize;
540
+ if (cy) {
541
+ cy.nodes().style('font-size', newFontSize + 'px');
542
+ }
543
+ });
544
+
545
+ // Initialize
546
+ updateUI();
547
+ </script>
548
+ </body>
549
+ </html>
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: codezoom
3
+ Version: 0.1.0.dev0
4
+ Summary: Multi-level code structure explorer — interactive drill-down HTML visualizations
5
+ Author: Curtis Rueden
6
+ License-Expression: Unlicense
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Topic :: Software Development :: Documentation
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+
13
+ # codezoom
14
+
15
+ Multi-level code structure explorer — interactive drill-down HTML visualizations.
16
+
17
+ codezoom generates a standalone HTML file that lets you explore a project's
18
+ structure at multiple levels of detail:
19
+
20
+ 1. **External dependencies** — direct and transitive packages from `pyproject.toml` + `uv.lock`
21
+ 2. **Package hierarchy** — sub-packages and modules (via [pydeps](https://github.com/thebjorn/pydeps) or file-tree fallback)
22
+ 3. **Module internals** — functions and classes extracted from the AST
23
+ 4. **Class internals** — methods and their call relationships
24
+
25
+ Click any node to drill down. Use breadcrumb navigation to go back up.
26
+
27
+ ## Examples
28
+
29
+ <table>
30
+ <tr>
31
+ <td align="center"><a href="screenshots/dependencies.png"><img src="screenshots/jgo-dependencies.png" width="400"></a><br><em>External dependencies</em></td>
32
+ <td align="center"><a href="screenshots/modules-1.png"><img src="screenshots/jgo-submodules.png" width="400"></a><br><em>Project submodules</em></td>
33
+ </tr>
34
+ <tr>
35
+ <td align="center"><a href="screenshots/modules-1a.png"><img src="screenshots/jgo-env.png" width="400"></a><br><em>A submodule's children</em></td>
36
+ <td align="center"><a href="screenshots/modules-2.png"><img src="screenshots/jgo-cli.png" width="400"></a><br><em>Another submodule's children</em></td>
37
+ </tr>
38
+ <tr>
39
+ <td align="center"><a href="screenshots/modules-3.png"><img src="screenshots/jgo-cli-rich-formatters.png" width="400"></a><br><em>Single-file view</em></td>
40
+ <td></td>
41
+ </tr>
42
+ </table>
43
+
44
+ ## Installation
45
+
46
+ <details><summary><strong>Installing codezoom with uv</strong></summary>
47
+
48
+ ```shell
49
+ uv tool install codezoom
50
+ ```
51
+
52
+ </details>
53
+ <details><summary><strong>Installing codezoom with pip</strong></summary>
54
+
55
+ ```shell
56
+ pip install codezoom
57
+ ```
58
+
59
+ </details>
60
+ <details><summary><strong>Installing codezoom from source</strong></summary>
61
+
62
+ ```shell
63
+ git clone https://github.com/apposed/codezoom
64
+ uv tool install --with-editable codezoom codezoom
65
+ ```
66
+
67
+ When installed in this fashion, changes to the codezoom source code will be immediately reflected when running `codezoom` from the command line.
68
+
69
+ </details>
70
+ <details><summary><strong>Using codezoom as a dependency</strong></summary>
71
+
72
+ ```shell
73
+ uv add codezoom
74
+ ```
75
+ or
76
+ ```shell
77
+ pixi add --pypi codezoom
78
+ ```
79
+ Not sure which to use? [Read this](https://jacobtomlinson.dev/posts/2025/python-package-managers-uv-vs-pixi/#so-what-do-i-use).
80
+
81
+ </details>
82
+
83
+ ## Usage
84
+
85
+ ```bash
86
+ codezoom /path/to/project # auto-detect, output to <project>_deps.html
87
+ codezoom /path/to/project -o output.html # custom output path
88
+ codezoom /path/to/project --name "My Project" # custom display name
89
+ codezoom /path/to/project --open # open in browser after generating
90
+ ```
91
+
92
+ Also works as a module:
93
+
94
+ ```bash
95
+ python -m codezoom /path/to/project
96
+ ```
97
+
98
+ ## Requirements
99
+
100
+ - Python 3.11+
101
+ - No mandatory runtime dependencies beyond the standard library
102
+ - Optional: [pydeps](https://github.com/thebjorn/pydeps) for richer module-level
103
+ import analysis (falls back to file-tree scanning without it)
104
+
105
+ ## Per-project configuration
106
+
107
+ Projects can include a `.codezoom.toml` or a `[tool.codezoom]` section in
108
+ `pyproject.toml`:
109
+
110
+ ```toml
111
+ [tool.codezoom]
112
+ exclude = ["tests", "docs", "__pycache__"]
113
+ ```
114
+
115
+ The `exclude` list is passed to pydeps via `-xx` to omit modules from the
116
+ hierarchy.
117
+
118
+ ## Language support
119
+
120
+ | Language | Status |
121
+ |----------|--------|
122
+ | Python | Supported |
123
+ | Java | Stub extractors present — not yet implemented |
124
+
125
+ ## License
126
+
127
+ [UNLICENSE](UNLICENSE) - All copyright disclaimed.
@@ -0,0 +1,20 @@
1
+ codezoom/__init__.py,sha256=jIjMCRyGDoY_6AwiQaoNO7pAoZokUAE9LPOQnKQBH0Y,56
2
+ codezoom/__main__.py,sha256=YzYrHTiuIa4igLWbSSaGkZWv0aKySM-EgEPy8s7OTso,84
3
+ codezoom/cli.py,sha256=gK-u1AKBjW1nREW-WRmvNHh0OSOLHqXG5L4VEQJrZyo,1161
4
+ codezoom/detect.py,sha256=qTpj8paVv8jzRk3DUePDrNDV1Q9ULJ-59C4wf1IKh0g,2037
5
+ codezoom/model.py,sha256=SlGYSACCjvXO103b7C8XoA4TX80AEIo_Sy9bXMTp4Qo,1261
6
+ codezoom/pipeline.py,sha256=BwjX4Haw6TZFJH-hANWUEGXLq09UCGU1mGw65BjgSME,3089
7
+ codezoom/extractors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ codezoom/extractors/base.py,sha256=-dBj5KO00bQkRMh9i5S5DwEkK_o3kX_YnE2ztuh2-zU,579
9
+ codezoom/extractors/java/__init__.py,sha256=nDWD0ocQw_Au_yynWSqvkoiWaEKvv-3XndKdh0MU9oY,1325
10
+ codezoom/extractors/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ codezoom/extractors/python/ast_symbols.py,sha256=y42gNw2lThOs5eoLqPz23tjnRwRzMmp9hgwR8wA1L7g,3973
12
+ codezoom/extractors/python/module_hierarchy.py,sha256=cmT-_48LHwZkDrQZd78b7ukvvoPi7JD1602QnOnxxNA,5559
13
+ codezoom/extractors/python/package_deps.py,sha256=38cW_ICfs-0vQ0emJOlQAMjtnprSf2BJ0R1gxRQ76G0,3519
14
+ codezoom/renderer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ codezoom/renderer/html.py,sha256=aACi7gWggy8R59bGlNdSTvvVv0GLS9b-MQf7dhvNQWI,2092
16
+ codezoom/renderer/template.html,sha256=w_Xd5lbArL4_AG9BBjIm9-WBXVQRS0qEDHjhEXQShAY,20526
17
+ codezoom-0.1.0.dev0.dist-info/METADATA,sha256=xAYckpyj9eKM7HSRbMRVgjkj-jPUAzDTyslaPqg7lNA,3981
18
+ codezoom-0.1.0.dev0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
19
+ codezoom-0.1.0.dev0.dist-info/entry_points.txt,sha256=XjcJlO6dz0CVGuAF2IFqYE9-i9AXdu-LXJKbKJuDv_g,47
20
+ codezoom-0.1.0.dev0.dist-info/RECORD,,