code2docs 0.1.4__tar.gz → 0.1.5__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.
- {code2docs-0.1.4 → code2docs-0.1.5}/PKG-INFO +2 -2
- {code2docs-0.1.4 → code2docs-0.1.5}/README.md +1 -1
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/__init__.py +1 -1
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/cli.py +43 -3
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/__init__.py +11 -0
- code2docs-0.1.5/code2docs/generators/api_changelog_gen.py +196 -0
- code2docs-0.1.5/code2docs/templates/module_doc.md.j2 +86 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs.egg-info/PKG-INFO +2 -2
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs.egg-info/SOURCES.txt +2 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/pyproject.toml +1 -1
- {code2docs-0.1.4 → code2docs-0.1.5}/LICENSE +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/__main__.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/analyzers/__init__.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/analyzers/dependency_scanner.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/analyzers/docstring_extractor.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/analyzers/endpoint_detector.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/analyzers/project_scanner.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/config.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/formatters/__init__.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/formatters/badges.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/formatters/markdown.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/formatters/toc.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/api_reference_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/architecture_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/changelog_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/coverage_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/depgraph_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/examples_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/mkdocs_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/module_docs_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/generators/readme_gen.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/sync/__init__.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/sync/differ.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/sync/updater.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/sync/watcher.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/templates/api_module.md.j2 +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/templates/architecture.md.j2 +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/templates/example_usage.py.j2 +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/templates/index.md.j2 +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs/templates/readme.md.j2 +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs.egg-info/dependency_links.txt +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs.egg-info/entry_points.txt +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs.egg-info/requires.txt +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/code2docs.egg-info/top_level.txt +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/setup.cfg +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/tests/test_analyzers.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/tests/test_code2docs.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/tests/test_config.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/tests/test_formatters.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/tests/test_generators.py +0 -0
- {code2docs-0.1.4 → code2docs-0.1.5}/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
|
+
Version: 0.1.5
|
|
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
|
-
  
|
|
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
|
-
  
|
|
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.
|
|
8
|
+
__version__ = "0.1.5"
|
|
9
9
|
__author__ = "Tom Sapletta"
|
|
10
10
|
|
|
11
11
|
from .config import Code2DocsConfig
|
|
@@ -115,6 +115,10 @@ def _run_generate(project_path: str, config: Code2DocsConfig,
|
|
|
115
115
|
from .generators.module_docs_gen import ModuleDocsGenerator
|
|
116
116
|
from .generators.examples_gen import ExamplesGenerator
|
|
117
117
|
from .generators.architecture_gen import ArchitectureGenerator
|
|
118
|
+
from .generators.depgraph_gen import DepGraphGenerator
|
|
119
|
+
from .generators.coverage_gen import CoverageGenerator
|
|
120
|
+
from .generators.mkdocs_gen import MkDocsGenerator
|
|
121
|
+
from .generators.api_changelog_gen import ApiChangelogGenerator
|
|
118
122
|
|
|
119
123
|
project = Path(project_path).resolve()
|
|
120
124
|
click.echo(f"📖 code2docs: analyzing {project.name}...")
|
|
@@ -169,13 +173,40 @@ def _run_generate(project_path: str, config: Code2DocsConfig,
|
|
|
169
173
|
arch_gen = ArchitectureGenerator(config, result)
|
|
170
174
|
content = arch_gen.generate()
|
|
171
175
|
if not dry_run:
|
|
172
|
-
|
|
173
|
-
arch_path.write_text(content, encoding="utf-8")
|
|
176
|
+
(docs_dir / "architecture.md").write_text(content, encoding="utf-8")
|
|
174
177
|
click.echo(f" ✅ docs/architecture.md")
|
|
175
178
|
else:
|
|
176
179
|
click.echo(f" [dry-run] docs/architecture.md")
|
|
177
180
|
|
|
178
|
-
# Step 4:
|
|
181
|
+
# Step 4: Dependency graph
|
|
182
|
+
depgraph_gen = DepGraphGenerator(config, result)
|
|
183
|
+
content = depgraph_gen.generate()
|
|
184
|
+
if not dry_run:
|
|
185
|
+
(docs_dir / "dependency-graph.md").write_text(content, encoding="utf-8")
|
|
186
|
+
click.echo(f" ✅ docs/dependency-graph.md")
|
|
187
|
+
else:
|
|
188
|
+
click.echo(f" [dry-run] docs/dependency-graph.md")
|
|
189
|
+
|
|
190
|
+
# Step 5: Docstring coverage
|
|
191
|
+
cov_gen = CoverageGenerator(config, result)
|
|
192
|
+
content = cov_gen.generate()
|
|
193
|
+
if not dry_run:
|
|
194
|
+
(docs_dir / "coverage.md").write_text(content, encoding="utf-8")
|
|
195
|
+
click.echo(f" ✅ docs/coverage.md")
|
|
196
|
+
else:
|
|
197
|
+
click.echo(f" [dry-run] docs/coverage.md")
|
|
198
|
+
|
|
199
|
+
# Step 6: API changelog (diff with previous snapshot)
|
|
200
|
+
api_cl_gen = ApiChangelogGenerator(config, result)
|
|
201
|
+
content = api_cl_gen.generate(str(project))
|
|
202
|
+
if not dry_run:
|
|
203
|
+
(docs_dir / "api-changelog.md").write_text(content, encoding="utf-8")
|
|
204
|
+
api_cl_gen.save_snapshot(str(project))
|
|
205
|
+
click.echo(f" ✅ docs/api-changelog.md")
|
|
206
|
+
else:
|
|
207
|
+
click.echo(f" [dry-run] docs/api-changelog.md")
|
|
208
|
+
|
|
209
|
+
# Step 7: Generate examples/
|
|
179
210
|
if config.examples.auto_generate:
|
|
180
211
|
ex_gen = ExamplesGenerator(config, result)
|
|
181
212
|
files = ex_gen.generate_all()
|
|
@@ -186,6 +217,15 @@ def _run_generate(project_path: str, config: Code2DocsConfig,
|
|
|
186
217
|
else:
|
|
187
218
|
click.echo(f" [dry-run] examples/ ({len(files)} files)")
|
|
188
219
|
|
|
220
|
+
# Step 8: mkdocs.yml
|
|
221
|
+
mkdocs_gen = MkDocsGenerator(config, result)
|
|
222
|
+
content = mkdocs_gen.generate(str(docs_dir))
|
|
223
|
+
if not dry_run:
|
|
224
|
+
mkdocs_gen.write(str(project / "mkdocs.yml"), content)
|
|
225
|
+
click.echo(f" ✅ mkdocs.yml")
|
|
226
|
+
else:
|
|
227
|
+
click.echo(f" [dry-run] mkdocs.yml")
|
|
228
|
+
|
|
189
229
|
click.echo("📖 Done!")
|
|
190
230
|
|
|
191
231
|
|
|
@@ -6,6 +6,10 @@ from .module_docs_gen import ModuleDocsGenerator
|
|
|
6
6
|
from .examples_gen import ExamplesGenerator
|
|
7
7
|
from .architecture_gen import ArchitectureGenerator
|
|
8
8
|
from .changelog_gen import ChangelogGenerator
|
|
9
|
+
from .depgraph_gen import DepGraphGenerator
|
|
10
|
+
from .coverage_gen import CoverageGenerator
|
|
11
|
+
from .mkdocs_gen import MkDocsGenerator
|
|
12
|
+
from .api_changelog_gen import ApiChangelogGenerator
|
|
9
13
|
|
|
10
14
|
__all__ = [
|
|
11
15
|
"ReadmeGenerator",
|
|
@@ -14,6 +18,10 @@ __all__ = [
|
|
|
14
18
|
"ExamplesGenerator",
|
|
15
19
|
"ArchitectureGenerator",
|
|
16
20
|
"ChangelogGenerator",
|
|
21
|
+
"DepGraphGenerator",
|
|
22
|
+
"CoverageGenerator",
|
|
23
|
+
"MkDocsGenerator",
|
|
24
|
+
"ApiChangelogGenerator",
|
|
17
25
|
"generate_docs",
|
|
18
26
|
]
|
|
19
27
|
|
|
@@ -39,4 +47,7 @@ def generate_docs(project_path: str, config=None):
|
|
|
39
47
|
if config.docs.architecture:
|
|
40
48
|
docs["architecture"] = ArchitectureGenerator(config, result).generate()
|
|
41
49
|
|
|
50
|
+
docs["dependency_graph"] = DepGraphGenerator(config, result).generate()
|
|
51
|
+
docs["coverage"] = CoverageGenerator(config, result).generate()
|
|
52
|
+
|
|
42
53
|
return docs
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""API changelog generator — diff function/class signatures between versions."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, List, Optional, Tuple
|
|
7
|
+
|
|
8
|
+
from code2llm.api import AnalysisResult
|
|
9
|
+
|
|
10
|
+
from ..config import Code2DocsConfig
|
|
11
|
+
|
|
12
|
+
SNAPSHOT_FILE = ".code2docs.api_snapshot.json"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class ApiChange:
|
|
17
|
+
"""A single API change between two analysis snapshots."""
|
|
18
|
+
kind: str # added, removed, changed
|
|
19
|
+
item_type: str # function, class, method
|
|
20
|
+
name: str
|
|
21
|
+
old_signature: str = ""
|
|
22
|
+
new_signature: str = ""
|
|
23
|
+
detail: str = ""
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def emoji(self) -> str:
|
|
27
|
+
return {"added": "🆕", "removed": "🗑️", "changed": "✏️"}.get(self.kind, "•")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ApiChangelogGenerator:
|
|
31
|
+
"""Generate API changelog by diffing current analysis with a saved snapshot."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, config: Code2DocsConfig, result: AnalysisResult):
|
|
34
|
+
self.config = config
|
|
35
|
+
self.result = result
|
|
36
|
+
|
|
37
|
+
def generate(self, project_path: str) -> str:
|
|
38
|
+
"""Generate api-changelog.md by comparing with previous snapshot."""
|
|
39
|
+
project = Path(project_path).resolve()
|
|
40
|
+
snapshot_path = project / SNAPSHOT_FILE
|
|
41
|
+
|
|
42
|
+
old_snapshot = self._load_snapshot(snapshot_path)
|
|
43
|
+
new_snapshot = self._build_snapshot()
|
|
44
|
+
changes = self._diff(old_snapshot, new_snapshot)
|
|
45
|
+
|
|
46
|
+
project_name = self.config.project_name or project.name
|
|
47
|
+
return self._render(project_name, changes, old_snapshot is not None)
|
|
48
|
+
|
|
49
|
+
def save_snapshot(self, project_path: str) -> None:
|
|
50
|
+
"""Save current API state as snapshot for future diffs."""
|
|
51
|
+
project = Path(project_path).resolve()
|
|
52
|
+
snapshot = self._build_snapshot()
|
|
53
|
+
path = project / SNAPSHOT_FILE
|
|
54
|
+
path.write_text(json.dumps(snapshot, indent=2), encoding="utf-8")
|
|
55
|
+
|
|
56
|
+
def _build_snapshot(self) -> Dict:
|
|
57
|
+
"""Build a JSON-serializable snapshot of current API."""
|
|
58
|
+
functions = {}
|
|
59
|
+
for name, func in self.result.functions.items():
|
|
60
|
+
if func.is_private:
|
|
61
|
+
continue
|
|
62
|
+
sig = f"{func.name}({', '.join(func.args)})"
|
|
63
|
+
if func.returns:
|
|
64
|
+
sig += f" → {func.returns}"
|
|
65
|
+
functions[name] = {
|
|
66
|
+
"signature": sig,
|
|
67
|
+
"is_method": func.is_method,
|
|
68
|
+
"module": func.module,
|
|
69
|
+
"docstring_hash": str(hash(func.docstring or ""))[:8],
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
classes = {}
|
|
73
|
+
for name, cls in self.result.classes.items():
|
|
74
|
+
classes[name] = {
|
|
75
|
+
"bases": cls.bases,
|
|
76
|
+
"methods": sorted(cls.methods),
|
|
77
|
+
"module": cls.module,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {"functions": functions, "classes": classes}
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def _load_snapshot(path: Path) -> Optional[Dict]:
|
|
84
|
+
"""Load previous snapshot, or None if not found."""
|
|
85
|
+
if not path.exists():
|
|
86
|
+
return None
|
|
87
|
+
try:
|
|
88
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
89
|
+
except (json.JSONDecodeError, OSError):
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
def _diff(self, old: Optional[Dict], new: Dict) -> List[ApiChange]:
|
|
93
|
+
"""Compute list of API changes between old and new snapshots."""
|
|
94
|
+
if old is None:
|
|
95
|
+
return []
|
|
96
|
+
|
|
97
|
+
changes: List[ApiChange] = []
|
|
98
|
+
self._diff_functions(old.get("functions", {}), new.get("functions", {}), changes)
|
|
99
|
+
self._diff_classes(old.get("classes", {}), new.get("classes", {}), changes)
|
|
100
|
+
return sorted(changes, key=lambda c: (c.kind, c.name))
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _diff_functions(old: Dict, new: Dict, changes: List[ApiChange]) -> None:
|
|
104
|
+
"""Diff function signatures."""
|
|
105
|
+
all_names = set(old.keys()) | set(new.keys())
|
|
106
|
+
for name in all_names:
|
|
107
|
+
old_fn = old.get(name)
|
|
108
|
+
new_fn = new.get(name)
|
|
109
|
+
item_type = "method" if (new_fn or old_fn or {}).get("is_method") else "function"
|
|
110
|
+
|
|
111
|
+
if old_fn and not new_fn:
|
|
112
|
+
changes.append(ApiChange(
|
|
113
|
+
kind="removed", item_type=item_type, name=name,
|
|
114
|
+
old_signature=old_fn["signature"],
|
|
115
|
+
))
|
|
116
|
+
elif new_fn and not old_fn:
|
|
117
|
+
changes.append(ApiChange(
|
|
118
|
+
kind="added", item_type=item_type, name=name,
|
|
119
|
+
new_signature=new_fn["signature"],
|
|
120
|
+
))
|
|
121
|
+
elif old_fn["signature"] != new_fn["signature"]:
|
|
122
|
+
changes.append(ApiChange(
|
|
123
|
+
kind="changed", item_type=item_type, name=name,
|
|
124
|
+
old_signature=old_fn["signature"],
|
|
125
|
+
new_signature=new_fn["signature"],
|
|
126
|
+
detail="signature changed",
|
|
127
|
+
))
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def _diff_classes(old: Dict, new: Dict, changes: List[ApiChange]) -> None:
|
|
131
|
+
"""Diff class definitions."""
|
|
132
|
+
all_names = set(old.keys()) | set(new.keys())
|
|
133
|
+
for name in all_names:
|
|
134
|
+
old_cls = old.get(name)
|
|
135
|
+
new_cls = new.get(name)
|
|
136
|
+
|
|
137
|
+
if old_cls and not new_cls:
|
|
138
|
+
changes.append(ApiChange(
|
|
139
|
+
kind="removed", item_type="class", name=name,
|
|
140
|
+
))
|
|
141
|
+
elif new_cls and not old_cls:
|
|
142
|
+
changes.append(ApiChange(
|
|
143
|
+
kind="added", item_type="class", name=name,
|
|
144
|
+
))
|
|
145
|
+
else:
|
|
146
|
+
diffs = []
|
|
147
|
+
if set(old_cls.get("bases", [])) != set(new_cls.get("bases", [])):
|
|
148
|
+
diffs.append("bases changed")
|
|
149
|
+
old_methods = set(old_cls.get("methods", []))
|
|
150
|
+
new_methods = set(new_cls.get("methods", []))
|
|
151
|
+
added = new_methods - old_methods
|
|
152
|
+
removed = old_methods - new_methods
|
|
153
|
+
if added:
|
|
154
|
+
diffs.append(f"added methods: {', '.join(sorted(added))}")
|
|
155
|
+
if removed:
|
|
156
|
+
diffs.append(f"removed methods: {', '.join(sorted(removed))}")
|
|
157
|
+
if diffs:
|
|
158
|
+
changes.append(ApiChange(
|
|
159
|
+
kind="changed", item_type="class", name=name,
|
|
160
|
+
detail="; ".join(diffs),
|
|
161
|
+
))
|
|
162
|
+
|
|
163
|
+
@staticmethod
|
|
164
|
+
def _render(project_name: str, changes: List[ApiChange], has_baseline: bool) -> str:
|
|
165
|
+
"""Render changelog as Markdown."""
|
|
166
|
+
lines = [f"# {project_name} — API Changelog\n"]
|
|
167
|
+
|
|
168
|
+
if not has_baseline:
|
|
169
|
+
lines.append(
|
|
170
|
+
"> No previous API snapshot found. Run `code2docs generate` to create a baseline.\n"
|
|
171
|
+
"> Future runs will show changes here.\n"
|
|
172
|
+
)
|
|
173
|
+
return "\n".join(lines)
|
|
174
|
+
|
|
175
|
+
if not changes:
|
|
176
|
+
lines.append("✅ **No API changes detected since last snapshot.**\n")
|
|
177
|
+
return "\n".join(lines)
|
|
178
|
+
|
|
179
|
+
lines.append(f"> {len(changes)} change(s) detected\n")
|
|
180
|
+
|
|
181
|
+
# Group by kind
|
|
182
|
+
for kind_label, kind_key in [("Added", "added"), ("Changed", "changed"), ("Removed", "removed")]:
|
|
183
|
+
group = [c for c in changes if c.kind == kind_key]
|
|
184
|
+
if not group:
|
|
185
|
+
continue
|
|
186
|
+
lines.append(f"## {kind_label}\n")
|
|
187
|
+
for c in group:
|
|
188
|
+
sig = c.new_signature or c.old_signature or c.name
|
|
189
|
+
lines.append(f"- {c.emoji} **{c.item_type}** `{sig}`")
|
|
190
|
+
if c.detail:
|
|
191
|
+
lines.append(f" - {c.detail}")
|
|
192
|
+
if c.kind == "changed" and c.old_signature and c.new_signature:
|
|
193
|
+
lines.append(f" - was: `{c.old_signature}`")
|
|
194
|
+
lines.append("")
|
|
195
|
+
|
|
196
|
+
return "\n".join(lines)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# {{ module_name }}
|
|
2
|
+
|
|
3
|
+
> Source: `{{ module_info.file }}`{% if file_lines %} | {{ file_lines }} lines{% endif %}{% if avg_cc %} | CC avg: {{ avg_cc }}{% endif %}
|
|
4
|
+
|
|
5
|
+
{% if module_docstring %}
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
{{ module_docstring }}
|
|
9
|
+
{% endif %}
|
|
10
|
+
|
|
11
|
+
{% if classes %}
|
|
12
|
+
## Classes
|
|
13
|
+
|
|
14
|
+
{% for cls_name, cls_info in classes.items() %}
|
|
15
|
+
### {{ cls_info.name }}
|
|
16
|
+
|
|
17
|
+
{% if cls_info.bases %}
|
|
18
|
+
*Bases:* {% for b in cls_info.bases %}`{{ b }}`{% if not loop.last %}, {% endif %}{% endfor %}
|
|
19
|
+
|
|
20
|
+
{% endif %}
|
|
21
|
+
{% if cls_info.docstring %}
|
|
22
|
+
{{ cls_info.docstring }}
|
|
23
|
+
|
|
24
|
+
{% endif %}
|
|
25
|
+
{% if methods[cls_name] %}
|
|
26
|
+
#### Methods
|
|
27
|
+
|
|
28
|
+
| Method | Args | Returns | CC |
|
|
29
|
+
|--------|------|---------|----|
|
|
30
|
+
{% for m in methods[cls_name] %}
|
|
31
|
+
{% set args = m.args[:4]|join(', ') %}
|
|
32
|
+
{% set ret = m.returns or '—' %}
|
|
33
|
+
{% set cc = m.complexity.get('cyclomatic', '—') %}
|
|
34
|
+
| `{{ m.name }}` | `{{ args }}` | `{{ ret }}` | {{ cc }} |
|
|
35
|
+
{% endfor %}
|
|
36
|
+
|
|
37
|
+
{% endif %}
|
|
38
|
+
{% endfor %}
|
|
39
|
+
{% endif %}
|
|
40
|
+
|
|
41
|
+
{% if functions %}
|
|
42
|
+
## Functions
|
|
43
|
+
|
|
44
|
+
{% for func_name, func_info in functions.items() %}
|
|
45
|
+
{% set args = func_info.args|join(', ') %}
|
|
46
|
+
{% set ret = ' → ' ~ func_info.returns if func_info.returns else '' %}
|
|
47
|
+
### `{{ func_info.name }}({{ args }}){{ ret }}`
|
|
48
|
+
|
|
49
|
+
{% if func_info.docstring %}
|
|
50
|
+
{{ func_info.docstring }}
|
|
51
|
+
|
|
52
|
+
{% endif %}
|
|
53
|
+
{% if func_info.calls %}
|
|
54
|
+
**Calls:** {% for c in func_info.calls[:10] %}`{{ c }}`{% if not loop.last %}, {% endif %}{% endfor %}
|
|
55
|
+
|
|
56
|
+
{% endif %}
|
|
57
|
+
{% endfor %}
|
|
58
|
+
{% endif %}
|
|
59
|
+
|
|
60
|
+
{% if imports %}
|
|
61
|
+
## Dependencies
|
|
62
|
+
|
|
63
|
+
{% if internal_imports %}
|
|
64
|
+
**Internal imports:**
|
|
65
|
+
{% for imp in internal_imports %}
|
|
66
|
+
- `{{ imp }}`
|
|
67
|
+
{% endfor %}
|
|
68
|
+
{% endif %}
|
|
69
|
+
|
|
70
|
+
{% if stdlib_imports %}
|
|
71
|
+
**Standard library:**
|
|
72
|
+
{% for imp in stdlib_imports %}
|
|
73
|
+
- `{{ imp }}`
|
|
74
|
+
{% endfor %}
|
|
75
|
+
{% endif %}
|
|
76
|
+
{% endif %}
|
|
77
|
+
|
|
78
|
+
{% if metrics %}
|
|
79
|
+
## Metrics
|
|
80
|
+
|
|
81
|
+
| Metric | Value |
|
|
82
|
+
|--------|-------|
|
|
83
|
+
{% for k, v in metrics.items() %}
|
|
84
|
+
| {{ k }} | {{ v }} |
|
|
85
|
+
{% endfor %}
|
|
86
|
+
{% endif %}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2docs
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
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
|
-
  
|
|
44
44
|
|
|
45
45
|
> Auto-generate and sync project documentation from source code analysis.
|
|
46
46
|
|
|
@@ -21,6 +21,7 @@ code2docs/formatters/badges.py
|
|
|
21
21
|
code2docs/formatters/markdown.py
|
|
22
22
|
code2docs/formatters/toc.py
|
|
23
23
|
code2docs/generators/__init__.py
|
|
24
|
+
code2docs/generators/api_changelog_gen.py
|
|
24
25
|
code2docs/generators/api_reference_gen.py
|
|
25
26
|
code2docs/generators/architecture_gen.py
|
|
26
27
|
code2docs/generators/changelog_gen.py
|
|
@@ -38,6 +39,7 @@ code2docs/templates/api_module.md.j2
|
|
|
38
39
|
code2docs/templates/architecture.md.j2
|
|
39
40
|
code2docs/templates/example_usage.py.j2
|
|
40
41
|
code2docs/templates/index.md.j2
|
|
42
|
+
code2docs/templates/module_doc.md.j2
|
|
41
43
|
code2docs/templates/readme.md.j2
|
|
42
44
|
tests/test_analyzers.py
|
|
43
45
|
tests/test_code2docs.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|