codezoom 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.
Files changed (31) hide show
  1. codezoom-0.1.0/.gitignore +4 -0
  2. codezoom-0.1.0/Makefile +18 -0
  3. codezoom-0.1.0/PKG-INFO +127 -0
  4. codezoom-0.1.0/README.md +115 -0
  5. codezoom-0.1.0/UNLICENSE +24 -0
  6. codezoom-0.1.0/bin/check.sh +6 -0
  7. codezoom-0.1.0/bin/clean.sh +9 -0
  8. codezoom-0.1.0/bin/dist.sh +6 -0
  9. codezoom-0.1.0/bin/lint.sh +24 -0
  10. codezoom-0.1.0/pyproject.toml +29 -0
  11. codezoom-0.1.0/screenshots/jgo-cli-rich-formatters.png +0 -0
  12. codezoom-0.1.0/screenshots/jgo-cli.png +0 -0
  13. codezoom-0.1.0/screenshots/jgo-dependencies.png +0 -0
  14. codezoom-0.1.0/screenshots/jgo-env.png +0 -0
  15. codezoom-0.1.0/screenshots/jgo-submodules.png +0 -0
  16. codezoom-0.1.0/src/codezoom/__init__.py +1 -0
  17. codezoom-0.1.0/src/codezoom/__main__.py +5 -0
  18. codezoom-0.1.0/src/codezoom/cli.py +47 -0
  19. codezoom-0.1.0/src/codezoom/detect.py +58 -0
  20. codezoom-0.1.0/src/codezoom/extractors/__init__.py +0 -0
  21. codezoom-0.1.0/src/codezoom/extractors/base.py +20 -0
  22. codezoom-0.1.0/src/codezoom/extractors/java/__init__.py +43 -0
  23. codezoom-0.1.0/src/codezoom/extractors/python/__init__.py +0 -0
  24. codezoom-0.1.0/src/codezoom/extractors/python/ast_symbols.py +120 -0
  25. codezoom-0.1.0/src/codezoom/extractors/python/module_hierarchy.py +171 -0
  26. codezoom-0.1.0/src/codezoom/extractors/python/package_deps.py +100 -0
  27. codezoom-0.1.0/src/codezoom/model.py +46 -0
  28. codezoom-0.1.0/src/codezoom/pipeline.py +96 -0
  29. codezoom-0.1.0/src/codezoom/renderer/__init__.py +0 -0
  30. codezoom-0.1.0/src/codezoom/renderer/html.py +64 -0
  31. codezoom-0.1.0/src/codezoom/renderer/template.html +549 -0
@@ -0,0 +1,4 @@
1
+ *.pyc
2
+ /dist/
3
+ /uv.lock
4
+ __pycache__/
@@ -0,0 +1,18 @@
1
+ help:
2
+ @echo "Available targets:\n\
3
+ clean - remove build files and directories\n\
4
+ lint - run code formatters and linters\n\
5
+ dist - generate release archives\n\
6
+ "
7
+
8
+ clean:
9
+ bin/clean.sh
10
+
11
+ check:
12
+ @bin/check.sh
13
+
14
+ lint: check
15
+ bin/lint.sh
16
+
17
+ dist: check clean
18
+ bin/dist.sh
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: codezoom
3
+ Version: 0.1.0
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,115 @@
1
+ # codezoom
2
+
3
+ Multi-level code structure explorer — interactive drill-down HTML visualizations.
4
+
5
+ codezoom generates a standalone HTML file that lets you explore a project's
6
+ structure at multiple levels of detail:
7
+
8
+ 1. **External dependencies** — direct and transitive packages from `pyproject.toml` + `uv.lock`
9
+ 2. **Package hierarchy** — sub-packages and modules (via [pydeps](https://github.com/thebjorn/pydeps) or file-tree fallback)
10
+ 3. **Module internals** — functions and classes extracted from the AST
11
+ 4. **Class internals** — methods and their call relationships
12
+
13
+ Click any node to drill down. Use breadcrumb navigation to go back up.
14
+
15
+ ## Examples
16
+
17
+ <table>
18
+ <tr>
19
+ <td align="center"><a href="screenshots/dependencies.png"><img src="screenshots/jgo-dependencies.png" width="400"></a><br><em>External dependencies</em></td>
20
+ <td align="center"><a href="screenshots/modules-1.png"><img src="screenshots/jgo-submodules.png" width="400"></a><br><em>Project submodules</em></td>
21
+ </tr>
22
+ <tr>
23
+ <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>
24
+ <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>
25
+ </tr>
26
+ <tr>
27
+ <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>
28
+ <td></td>
29
+ </tr>
30
+ </table>
31
+
32
+ ## Installation
33
+
34
+ <details><summary><strong>Installing codezoom with uv</strong></summary>
35
+
36
+ ```shell
37
+ uv tool install codezoom
38
+ ```
39
+
40
+ </details>
41
+ <details><summary><strong>Installing codezoom with pip</strong></summary>
42
+
43
+ ```shell
44
+ pip install codezoom
45
+ ```
46
+
47
+ </details>
48
+ <details><summary><strong>Installing codezoom from source</strong></summary>
49
+
50
+ ```shell
51
+ git clone https://github.com/apposed/codezoom
52
+ uv tool install --with-editable codezoom codezoom
53
+ ```
54
+
55
+ When installed in this fashion, changes to the codezoom source code will be immediately reflected when running `codezoom` from the command line.
56
+
57
+ </details>
58
+ <details><summary><strong>Using codezoom as a dependency</strong></summary>
59
+
60
+ ```shell
61
+ uv add codezoom
62
+ ```
63
+ or
64
+ ```shell
65
+ pixi add --pypi codezoom
66
+ ```
67
+ Not sure which to use? [Read this](https://jacobtomlinson.dev/posts/2025/python-package-managers-uv-vs-pixi/#so-what-do-i-use).
68
+
69
+ </details>
70
+
71
+ ## Usage
72
+
73
+ ```bash
74
+ codezoom /path/to/project # auto-detect, output to <project>_deps.html
75
+ codezoom /path/to/project -o output.html # custom output path
76
+ codezoom /path/to/project --name "My Project" # custom display name
77
+ codezoom /path/to/project --open # open in browser after generating
78
+ ```
79
+
80
+ Also works as a module:
81
+
82
+ ```bash
83
+ python -m codezoom /path/to/project
84
+ ```
85
+
86
+ ## Requirements
87
+
88
+ - Python 3.11+
89
+ - No mandatory runtime dependencies beyond the standard library
90
+ - Optional: [pydeps](https://github.com/thebjorn/pydeps) for richer module-level
91
+ import analysis (falls back to file-tree scanning without it)
92
+
93
+ ## Per-project configuration
94
+
95
+ Projects can include a `.codezoom.toml` or a `[tool.codezoom]` section in
96
+ `pyproject.toml`:
97
+
98
+ ```toml
99
+ [tool.codezoom]
100
+ exclude = ["tests", "docs", "__pycache__"]
101
+ ```
102
+
103
+ The `exclude` list is passed to pydeps via `-xx` to omit modules from the
104
+ hierarchy.
105
+
106
+ ## Language support
107
+
108
+ | Language | Status |
109
+ |----------|--------|
110
+ | Python | Supported |
111
+ | Java | Stub extractors present — not yet implemented |
112
+
113
+ ## License
114
+
115
+ [UNLICENSE](UNLICENSE) - All copyright disclaimed.
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ if ! command -v uv >/dev/null 2>&1; then
4
+ echo "Please install uv (https://docs.astral.sh/uv/getting-started/installation/)."
5
+ exit 1
6
+ fi
@@ -0,0 +1,9 @@
1
+ #!/bin/sh
2
+
3
+ dir=$(dirname "$0")
4
+ cd "$dir/.."
5
+
6
+ find . -name __pycache__ -type d | while read d
7
+ do rm -rfv "$d"
8
+ done
9
+ rm -rfv .mypy_cache .pytest_cache build dist src/*.egg-info
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+
3
+ dir=$(dirname "$0")
4
+ cd "$dir/.."
5
+
6
+ uv run python -m build
@@ -0,0 +1,24 @@
1
+ #!/bin/sh
2
+
3
+ dir=$(dirname "$0")
4
+ cd "$dir/.."
5
+
6
+ exitCode=0
7
+
8
+ # Check for errors and capture non-zero exit codes.
9
+ uv run validate-pyproject pyproject.toml
10
+ code=$?; test $code -eq 0 || exitCode=$code
11
+ uv run ruff check >/dev/null 2>&1
12
+ code=$?; test $code -eq 0 || exitCode=$code
13
+ uv run ruff format --check >/dev/null 2>&1
14
+ code=$?; test $code -eq 0 || exitCode=$code
15
+
16
+ # Do actual code reformatting.
17
+ uv run ruff check --select I --fix
18
+ code=$?; test $code -eq 0 || exitCode=$code
19
+ uv run ruff check --fix
20
+ code=$?; test $code -eq 0 || exitCode=$code
21
+ uv run ruff format
22
+ code=$?; test $code -eq 0 || exitCode=$code
23
+
24
+ exit $exitCode
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "codezoom"
7
+ version = "0.1.0"
8
+ description = "Multi-level code structure explorer — interactive drill-down HTML visualizations"
9
+ readme = "README.md"
10
+ license = "Unlicense"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ { name = "Curtis Rueden" },
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Programming Language :: Python :: 3",
18
+ "Topic :: Software Development :: Documentation",
19
+ ]
20
+
21
+ [dependency-groups]
22
+ dev = [
23
+ "build",
24
+ "ruff",
25
+ "validate-pyproject[all]",
26
+ ]
27
+
28
+ [project.scripts]
29
+ codezoom = "codezoom.cli:main"
Binary file
Binary file
@@ -0,0 +1 @@
1
+ """codezoom — Multi-level code structure explorer."""
@@ -0,0 +1,5 @@
1
+ """Allow running as `python -m codezoom`."""
2
+
3
+ from codezoom.cli import main
4
+
5
+ main()
@@ -0,0 +1,47 @@
1
+ """Command-line interface for codezoom."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from pathlib import Path
7
+
8
+ from codezoom.pipeline import run
9
+
10
+
11
+ def main(argv: list[str] | None = None) -> None:
12
+ parser = argparse.ArgumentParser(
13
+ prog="codezoom",
14
+ description="Multi-level code structure explorer — interactive drill-down HTML visualizations.",
15
+ )
16
+ parser.add_argument(
17
+ "project_dir",
18
+ type=Path,
19
+ help="Path to the project to visualize",
20
+ )
21
+ parser.add_argument(
22
+ "-o",
23
+ "--output",
24
+ type=Path,
25
+ default=None,
26
+ help="Output HTML file path (default: <project>_deps.html)",
27
+ )
28
+ parser.add_argument(
29
+ "--name",
30
+ default=None,
31
+ help="Project display name (default: auto-detect from pyproject.toml)",
32
+ )
33
+ parser.add_argument(
34
+ "--open",
35
+ action="store_true",
36
+ dest="open_browser",
37
+ help="Open the generated HTML in a browser",
38
+ )
39
+
40
+ args = parser.parse_args(argv)
41
+
42
+ run(
43
+ args.project_dir,
44
+ output=args.output,
45
+ name=args.name,
46
+ open_browser=args.open_browser,
47
+ )
@@ -0,0 +1,58 @@
1
+ """Auto-detect project type and return appropriate extractors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from codezoom.extractors.base import Extractor
9
+ from codezoom.extractors.python.ast_symbols import AstSymbolsExtractor
10
+ from codezoom.extractors.python.module_hierarchy import ModuleHierarchyExtractor
11
+ from codezoom.extractors.python.package_deps import PackageDepsExtractor
12
+
13
+
14
+ def detect_extractors(project_dir: Path, project_name: str) -> list[Extractor]:
15
+ """Return an ordered list of extractors applicable to *project_dir*."""
16
+ extractors: list[Extractor] = []
17
+
18
+ if (project_dir / "pyproject.toml").exists():
19
+ # Read optional codezoom config
20
+ exclude = _read_config_exclude(project_dir, project_name)
21
+ extractors.append(PackageDepsExtractor())
22
+ extractors.append(ModuleHierarchyExtractor(exclude=exclude))
23
+ extractors.append(AstSymbolsExtractor())
24
+
25
+ if (project_dir / "pom.xml").exists() or (project_dir / "build.gradle").exists():
26
+ print(
27
+ "Note: Java project detected — Java support coming soon.",
28
+ file=sys.stderr,
29
+ )
30
+
31
+ return extractors
32
+
33
+
34
+ def _read_config_exclude(project_dir: Path, project_name: str) -> list[str] | None:
35
+ """Read pydeps exclude list from .codezoom.toml or pyproject.toml."""
36
+ import tomllib
37
+
38
+ # Try .codezoom.toml first
39
+ codezoom_toml = project_dir / ".codezoom.toml"
40
+ if codezoom_toml.exists():
41
+ try:
42
+ with open(codezoom_toml, "rb") as f:
43
+ data = tomllib.load(f)
44
+ return data.get("codezoom", {}).get("exclude", None)
45
+ except Exception:
46
+ pass
47
+
48
+ # Fall back to [tool.codezoom] in pyproject.toml
49
+ pyproject = project_dir / "pyproject.toml"
50
+ if pyproject.exists():
51
+ try:
52
+ with open(pyproject, "rb") as f:
53
+ data = tomllib.load(f)
54
+ return data.get("tool", {}).get("codezoom", {}).get("exclude", None)
55
+ except Exception:
56
+ pass
57
+
58
+ return None
File without changes
@@ -0,0 +1,20 @@
1
+ """Extractor protocol — all extractors conform to this interface."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Protocol
7
+
8
+ from codezoom.model import ProjectGraph
9
+
10
+
11
+ class Extractor(Protocol):
12
+ """Protocol for project structure extractors."""
13
+
14
+ def can_handle(self, project_dir: Path) -> bool:
15
+ """Return True if this extractor applies to the given project."""
16
+ ...
17
+
18
+ def extract(self, project_dir: Path, graph: ProjectGraph) -> None:
19
+ """Populate *graph* with data extracted from *project_dir*."""
20
+ ...
@@ -0,0 +1,43 @@
1
+ """Java extractors — stubs for future implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from codezoom.model import ProjectGraph
8
+
9
+
10
+ class JavaMavenDeps:
11
+ """Extract dependencies from pom.xml / build.gradle. (Not yet implemented.)"""
12
+
13
+ def can_handle(self, project_dir: Path) -> bool:
14
+ return (project_dir / "pom.xml").exists() or (
15
+ project_dir / "build.gradle"
16
+ ).exists()
17
+
18
+ def extract(self, project_dir: Path, graph: ProjectGraph) -> None:
19
+ pass # TODO: parse pom.xml / build.gradle
20
+
21
+
22
+ class JavaPackageHierarchy:
23
+ """Extract Java package/class hierarchy. (Not yet implemented.)"""
24
+
25
+ def can_handle(self, project_dir: Path) -> bool:
26
+ return (project_dir / "pom.xml").exists() or (
27
+ project_dir / "build.gradle"
28
+ ).exists()
29
+
30
+ def extract(self, project_dir: Path, graph: ProjectGraph) -> None:
31
+ pass # TODO: walk src/main/java tree
32
+
33
+
34
+ class JavaAstSymbols:
35
+ """Extract methods/fields from Java classes. (Not yet implemented.)"""
36
+
37
+ def can_handle(self, project_dir: Path) -> bool:
38
+ return (project_dir / "pom.xml").exists() or (
39
+ project_dir / "build.gradle"
40
+ ).exists()
41
+
42
+ def extract(self, project_dir: Path, graph: ProjectGraph) -> None:
43
+ pass # TODO: parse Java AST