code2docs 0.1.3__tar.gz → 0.1.4__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 (49) hide show
  1. {code2docs-0.1.3 → code2docs-0.1.4}/PKG-INFO +2 -2
  2. {code2docs-0.1.3 → code2docs-0.1.4}/README.md +1 -1
  3. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/__init__.py +1 -1
  4. code2docs-0.1.4/code2docs/generators/coverage_gen.py +85 -0
  5. code2docs-0.1.4/code2docs/generators/depgraph_gen.py +112 -0
  6. code2docs-0.1.4/code2docs/generators/mkdocs_gen.py +79 -0
  7. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs.egg-info/PKG-INFO +2 -2
  8. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs.egg-info/SOURCES.txt +3 -0
  9. {code2docs-0.1.3 → code2docs-0.1.4}/pyproject.toml +1 -1
  10. {code2docs-0.1.3 → code2docs-0.1.4}/LICENSE +0 -0
  11. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/__main__.py +0 -0
  12. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/analyzers/__init__.py +0 -0
  13. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/analyzers/dependency_scanner.py +0 -0
  14. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/analyzers/docstring_extractor.py +0 -0
  15. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/analyzers/endpoint_detector.py +0 -0
  16. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/analyzers/project_scanner.py +0 -0
  17. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/cli.py +0 -0
  18. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/config.py +0 -0
  19. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/formatters/__init__.py +0 -0
  20. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/formatters/badges.py +0 -0
  21. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/formatters/markdown.py +0 -0
  22. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/formatters/toc.py +0 -0
  23. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/generators/__init__.py +0 -0
  24. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/generators/api_reference_gen.py +0 -0
  25. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/generators/architecture_gen.py +0 -0
  26. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/generators/changelog_gen.py +0 -0
  27. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/generators/examples_gen.py +0 -0
  28. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/generators/module_docs_gen.py +0 -0
  29. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/generators/readme_gen.py +0 -0
  30. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/sync/__init__.py +0 -0
  31. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/sync/differ.py +0 -0
  32. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/sync/updater.py +0 -0
  33. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/sync/watcher.py +0 -0
  34. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/templates/api_module.md.j2 +0 -0
  35. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/templates/architecture.md.j2 +0 -0
  36. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/templates/example_usage.py.j2 +0 -0
  37. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/templates/index.md.j2 +0 -0
  38. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs/templates/readme.md.j2 +0 -0
  39. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs.egg-info/dependency_links.txt +0 -0
  40. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs.egg-info/entry_points.txt +0 -0
  41. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs.egg-info/requires.txt +0 -0
  42. {code2docs-0.1.3 → code2docs-0.1.4}/code2docs.egg-info/top_level.txt +0 -0
  43. {code2docs-0.1.3 → code2docs-0.1.4}/setup.cfg +0 -0
  44. {code2docs-0.1.3 → code2docs-0.1.4}/tests/test_analyzers.py +0 -0
  45. {code2docs-0.1.3 → code2docs-0.1.4}/tests/test_code2docs.py +0 -0
  46. {code2docs-0.1.3 → code2docs-0.1.4}/tests/test_config.py +0 -0
  47. {code2docs-0.1.3 → code2docs-0.1.4}/tests/test_formatters.py +0 -0
  48. {code2docs-0.1.3 → code2docs-0.1.4}/tests/test_generators.py +0 -0
  49. {code2docs-0.1.3 → code2docs-0.1.4}/tests/test_sync.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code2docs
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Auto-generate and sync project documentation from source code analysis
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -40,7 +40,7 @@ Dynamic: license-file
40
40
 
41
41
  # code2docs
42
42
 
43
- ![version](https://img.shields.io/badge/version-0.1.3-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
43
+ ![version](https://img.shields.io/badge/version-0.1.4-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
44
44
 
45
45
  > Auto-generate and sync project documentation from source code analysis.
46
46
 
@@ -1,6 +1,6 @@
1
1
  # code2docs
2
2
 
3
- ![version](https://img.shields.io/badge/version-0.1.3-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
3
+ ![version](https://img.shields.io/badge/version-0.1.4-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
4
4
 
5
5
  > Auto-generate and sync project documentation from source code analysis.
6
6
 
@@ -5,7 +5,7 @@ Uses code2llm's AnalysisResult to produce human-readable documentation:
5
5
  README.md, API references, module docs, examples, and architecture diagrams.
6
6
  """
7
7
 
8
- __version__ = "0.1.3"
8
+ __version__ = "0.1.4"
9
9
  __author__ = "Tom Sapletta"
10
10
 
11
11
  from .config import Code2DocsConfig
@@ -0,0 +1,85 @@
1
+ """Docstring coverage report generator."""
2
+
3
+ from typing import Dict, List
4
+
5
+ from code2llm.api import AnalysisResult
6
+
7
+ from ..config import Code2DocsConfig
8
+ from ..analyzers.docstring_extractor import DocstringExtractor
9
+
10
+
11
+ class CoverageGenerator:
12
+ """Generate docs/coverage.md — docstring coverage report."""
13
+
14
+ def __init__(self, config: Code2DocsConfig, result: AnalysisResult):
15
+ self.config = config
16
+ self.result = result
17
+ self._extractor = DocstringExtractor()
18
+
19
+ def generate(self) -> str:
20
+ """Generate coverage.md content."""
21
+ project_name = self.config.project_name or "Project"
22
+ report = self._extractor.coverage_report(self.result)
23
+
24
+ lines = [
25
+ f"# {project_name} — Docstring Coverage\n",
26
+ self._render_summary(report),
27
+ "",
28
+ "## Per-Module Breakdown\n",
29
+ self._render_per_module(),
30
+ "",
31
+ "## Undocumented Items\n",
32
+ self._render_undocumented(),
33
+ "",
34
+ ]
35
+ return "\n".join(lines)
36
+
37
+ @staticmethod
38
+ def _render_summary(report: Dict[str, float]) -> str:
39
+ """Render overall coverage summary."""
40
+ overall = report.get("overall_coverage", 0)
41
+ badge = "🟢" if overall >= 80 else "🟡" if overall >= 50 else "🔴"
42
+ lines = [
43
+ f"{badge} **Overall coverage: {overall:.1f}%**\n",
44
+ "| Category | Documented | Total | Coverage |",
45
+ "|----------|-----------|-------|----------|",
46
+ f"| Functions | {report['functions_documented']} | {report['functions_total']} | {report['functions_coverage']:.1f}% |",
47
+ f"| Classes | {report['classes_documented']} | {report['classes_total']} | {report['classes_coverage']:.1f}% |",
48
+ ]
49
+ return "\n".join(lines)
50
+
51
+ def _render_per_module(self) -> str:
52
+ """Render per-module coverage table."""
53
+ rows: List[str] = [
54
+ "| Module | Functions | Classes | Coverage |",
55
+ "|--------|-----------|---------|----------|",
56
+ ]
57
+ for mod_name in sorted(self.result.modules.keys()):
58
+ funcs = [f for f in self.result.functions.values()
59
+ if f.module == mod_name and not f.is_method]
60
+ classes = [c for c in self.result.classes.values()
61
+ if c.module == mod_name]
62
+ total = len(funcs) + len(classes)
63
+ documented = (sum(1 for f in funcs if f.docstring) +
64
+ sum(1 for c in classes if c.docstring))
65
+ pct = (documented / total * 100) if total else 100.0
66
+ badge = "🟢" if pct >= 80 else "🟡" if pct >= 50 else "🔴"
67
+ rows.append(
68
+ f"| `{mod_name}` | {sum(1 for f in funcs if f.docstring)}/{len(funcs)} "
69
+ f"| {sum(1 for c in classes if c.docstring)}/{len(classes)} "
70
+ f"| {badge} {pct:.0f}% |"
71
+ )
72
+ return "\n".join(rows)
73
+
74
+ def _render_undocumented(self) -> str:
75
+ """List all undocumented public functions and classes."""
76
+ items: List[str] = []
77
+ for name, func in sorted(self.result.functions.items()):
78
+ if not func.docstring and not func.is_private and not func.is_method:
79
+ items.append(f"- `{name}` ({func.file}:{func.line})")
80
+ for name, cls in sorted(self.result.classes.items()):
81
+ if not cls.docstring:
82
+ items.append(f"- `{name}` ({cls.file}:{cls.line})")
83
+ if not items:
84
+ return "_All public items are documented._ ✅"
85
+ return "\n".join(items)
@@ -0,0 +1,112 @@
1
+ """Dependency graph generator — Mermaid diagram from coupling matrix."""
2
+
3
+ from typing import Dict, List, Set, Tuple
4
+
5
+ from code2llm.api import AnalysisResult, ModuleInfo
6
+
7
+ from ..config import Code2DocsConfig
8
+
9
+
10
+ class DepGraphGenerator:
11
+ """Generate docs/dependency-graph.md with Mermaid diagrams."""
12
+
13
+ def __init__(self, config: Code2DocsConfig, result: AnalysisResult):
14
+ self.config = config
15
+ self.result = result
16
+
17
+ def generate(self) -> str:
18
+ """Generate dependency-graph.md content."""
19
+ project_name = self.config.project_name or "Project"
20
+ edges = self._collect_edges()
21
+ in_degree, out_degree = self._calc_degrees(edges)
22
+
23
+ lines = [
24
+ f"# {project_name} — Dependency Graph\n",
25
+ f"> {len(self.result.modules)} modules, "
26
+ f"{len(edges)} dependency edges\n",
27
+ "## Module Dependencies\n",
28
+ self._render_mermaid(edges),
29
+ "",
30
+ "## Coupling Matrix\n",
31
+ self._render_matrix(edges),
32
+ "",
33
+ "## Fan-in / Fan-out\n",
34
+ self._render_degree_table(in_degree, out_degree),
35
+ "",
36
+ ]
37
+ return "\n".join(lines)
38
+
39
+ def _collect_edges(self) -> List[Tuple[str, str]]:
40
+ """Build directed edges from module imports."""
41
+ edges: List[Tuple[str, str]] = []
42
+ module_names = set(self.result.modules.keys())
43
+
44
+ for mod_name, mod_info in self.result.modules.items():
45
+ for imp in mod_info.imports:
46
+ for other in module_names:
47
+ if mod_name != other and self._import_matches(imp, other):
48
+ edges.append((mod_name, other))
49
+ return sorted(set(edges))
50
+
51
+ @staticmethod
52
+ def _import_matches(imp: str, module: str) -> bool:
53
+ """Check if an import string refers to a known module."""
54
+ return imp == module or imp.startswith(module + ".")
55
+
56
+ def _render_mermaid(self, edges: List[Tuple[str, str]]) -> str:
57
+ """Render Mermaid graph from edges."""
58
+ lines = ["```mermaid", "graph LR"]
59
+ for src, tgt in edges:
60
+ s = src.split(".")[-1]
61
+ t = tgt.split(".")[-1]
62
+ lines.append(f" {s} --> {t}")
63
+ if not edges:
64
+ lines.append(" note[No internal dependencies]")
65
+ lines.append("```")
66
+ return "\n".join(lines)
67
+
68
+ def _render_matrix(self, edges: List[Tuple[str, str]]) -> str:
69
+ """Render a coupling matrix as a Markdown table."""
70
+ mods = sorted(self.result.modules.keys())
71
+ if not mods:
72
+ return "_No modules._"
73
+ short = {m: m.split(".")[-1] for m in mods}
74
+ edge_set = set(edges)
75
+
76
+ header = "| | " + " | ".join(short[m] for m in mods) + " |"
77
+ sep = "| --- | " + " | ".join("---" for _ in mods) + " |"
78
+ rows = [header, sep]
79
+ for src in mods:
80
+ cells = []
81
+ for tgt in mods:
82
+ if src == tgt:
83
+ cells.append("·")
84
+ elif (src, tgt) in edge_set:
85
+ cells.append("→")
86
+ else:
87
+ cells.append("")
88
+ rows.append(f"| **{short[src]}** | " + " | ".join(cells) + " |")
89
+ return "\n".join(rows)
90
+
91
+ @staticmethod
92
+ def _calc_degrees(edges: List[Tuple[str, str]]) -> Tuple[Dict[str, int], Dict[str, int]]:
93
+ """Calculate in-degree and out-degree per module."""
94
+ in_deg: Dict[str, int] = {}
95
+ out_deg: Dict[str, int] = {}
96
+ for src, tgt in edges:
97
+ out_deg[src] = out_deg.get(src, 0) + 1
98
+ in_deg[tgt] = in_deg.get(tgt, 0) + 1
99
+ return in_deg, out_deg
100
+
101
+ def _render_degree_table(self, in_deg: Dict[str, int], out_deg: Dict[str, int]) -> str:
102
+ """Render fan-in/fan-out table."""
103
+ mods = sorted(self.result.modules.keys())
104
+ lines = [
105
+ "| Module | Fan-in | Fan-out |",
106
+ "|--------|--------|---------|",
107
+ ]
108
+ for m in mods:
109
+ fi = in_deg.get(m, 0)
110
+ fo = out_deg.get(m, 0)
111
+ lines.append(f"| `{m}` | {fi} | {fo} |")
112
+ return "\n".join(lines)
@@ -0,0 +1,79 @@
1
+ """MkDocs configuration generator — auto-generate mkdocs.yml from docs tree."""
2
+
3
+ from pathlib import Path
4
+ from typing import Dict, List, Optional
5
+
6
+ import yaml
7
+
8
+ from code2llm.api import AnalysisResult
9
+
10
+ from ..config import Code2DocsConfig
11
+
12
+
13
+ class MkDocsGenerator:
14
+ """Generate mkdocs.yml from the docs/ directory structure."""
15
+
16
+ def __init__(self, config: Code2DocsConfig, result: AnalysisResult):
17
+ self.config = config
18
+ self.result = result
19
+
20
+ def generate(self, docs_dir: Optional[str] = None) -> str:
21
+ """Generate mkdocs.yml content."""
22
+ project_name = self.config.project_name or "Project"
23
+ nav = self._build_nav(docs_dir)
24
+
25
+ data = {
26
+ "site_name": f"{project_name} Documentation",
27
+ "theme": {"name": "material"},
28
+ "nav": nav,
29
+ "markdown_extensions": [
30
+ "admonition",
31
+ "pymdownx.highlight",
32
+ "pymdownx.superfences",
33
+ {"pymdownx.superfences": {
34
+ "custom_fences": [{
35
+ "name": "mermaid",
36
+ "class": "mermaid",
37
+ "format": "!!python/name:pymdownx.superfences.fence_code_format",
38
+ }]
39
+ }},
40
+ ],
41
+ }
42
+ return yaml.dump(data, default_flow_style=False, sort_keys=False)
43
+
44
+ def _build_nav(self, docs_dir: Optional[str] = None) -> List:
45
+ """Build navigation structure from docs tree and analysis."""
46
+ nav: List = [{"Home": "index.md"}]
47
+
48
+ if self.config.docs.architecture:
49
+ nav.append({"Architecture": "architecture.md"})
50
+
51
+ # API reference
52
+ if self.config.docs.api_reference:
53
+ api_items = [{"Overview": "api/index.md"}]
54
+ for mod_name in sorted(self.result.modules.keys()):
55
+ safe = mod_name.replace(".", "_").replace("/", "_")
56
+ api_items.append({mod_name: f"api/module_{safe}.md"})
57
+ nav.append({"API Reference": api_items})
58
+
59
+ # Module docs
60
+ if self.config.docs.module_docs:
61
+ mod_items = []
62
+ for mod_name in sorted(self.result.modules.keys()):
63
+ safe = mod_name.replace(".", "_").replace("/", "_")
64
+ mod_items.append({mod_name: f"modules/{safe}.md"})
65
+ if mod_items:
66
+ nav.append({"Modules": mod_items})
67
+
68
+ # Extra pages
69
+ nav.append({"Dependency Graph": "dependency-graph.md"})
70
+ nav.append({"Coverage": "coverage.md"})
71
+
72
+ if self.config.docs.changelog:
73
+ nav.append({"Changelog": "changelog.md"})
74
+
75
+ return nav
76
+
77
+ def write(self, output_path: str, content: str) -> None:
78
+ """Write mkdocs.yml file."""
79
+ Path(output_path).write_text(content, encoding="utf-8")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code2docs
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Auto-generate and sync project documentation from source code analysis
5
5
  Author-email: Tom Sapletta <tom@sapletta.com>
6
6
  License-Expression: Apache-2.0
@@ -40,7 +40,7 @@ Dynamic: license-file
40
40
 
41
41
  # code2docs
42
42
 
43
- ![version](https://img.shields.io/badge/version-0.1.3-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
43
+ ![version](https://img.shields.io/badge/version-0.1.4-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![docs](https://img.shields.io/badge/docs-auto--generated-blueviolet)
44
44
 
45
45
  > Auto-generate and sync project documentation from source code analysis.
46
46
 
@@ -24,7 +24,10 @@ code2docs/generators/__init__.py
24
24
  code2docs/generators/api_reference_gen.py
25
25
  code2docs/generators/architecture_gen.py
26
26
  code2docs/generators/changelog_gen.py
27
+ code2docs/generators/coverage_gen.py
28
+ code2docs/generators/depgraph_gen.py
27
29
  code2docs/generators/examples_gen.py
30
+ code2docs/generators/mkdocs_gen.py
28
31
  code2docs/generators/module_docs_gen.py
29
32
  code2docs/generators/readme_gen.py
30
33
  code2docs/sync/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code2docs"
7
- version = "0.1.3"
7
+ version = "0.1.4"
8
8
  description = "Auto-generate and sync project documentation from source code analysis"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes
File without changes
File without changes
File without changes
File without changes