code2docs 0.1.6__tar.gz → 0.2.1__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 (52) hide show
  1. {code2docs-0.1.6 → code2docs-0.2.1}/PKG-INFO +3 -3
  2. {code2docs-0.1.6 → code2docs-0.2.1}/README.md +2 -2
  3. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/__init__.py +1 -1
  4. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/depgraph_gen.py +33 -5
  5. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs.egg-info/PKG-INFO +3 -3
  6. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs.egg-info/SOURCES.txt +1 -0
  7. {code2docs-0.1.6 → code2docs-0.2.1}/pyproject.toml +1 -1
  8. code2docs-0.2.1/tests/test_cli.py +67 -0
  9. {code2docs-0.1.6 → code2docs-0.2.1}/LICENSE +0 -0
  10. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/__main__.py +0 -0
  11. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/analyzers/__init__.py +0 -0
  12. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/analyzers/dependency_scanner.py +0 -0
  13. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/analyzers/docstring_extractor.py +0 -0
  14. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/analyzers/endpoint_detector.py +0 -0
  15. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/analyzers/project_scanner.py +0 -0
  16. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/cli.py +0 -0
  17. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/config.py +0 -0
  18. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/formatters/__init__.py +0 -0
  19. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/formatters/badges.py +0 -0
  20. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/formatters/markdown.py +0 -0
  21. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/formatters/toc.py +0 -0
  22. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/__init__.py +0 -0
  23. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/api_changelog_gen.py +0 -0
  24. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/api_reference_gen.py +0 -0
  25. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/architecture_gen.py +0 -0
  26. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/changelog_gen.py +0 -0
  27. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/coverage_gen.py +0 -0
  28. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/examples_gen.py +0 -0
  29. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/mkdocs_gen.py +0 -0
  30. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/module_docs_gen.py +0 -0
  31. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/generators/readme_gen.py +0 -0
  32. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/sync/__init__.py +0 -0
  33. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/sync/differ.py +0 -0
  34. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/sync/updater.py +0 -0
  35. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/sync/watcher.py +0 -0
  36. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/templates/api_module.md.j2 +0 -0
  37. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/templates/architecture.md.j2 +0 -0
  38. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/templates/example_usage.py.j2 +0 -0
  39. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/templates/index.md.j2 +0 -0
  40. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/templates/module_doc.md.j2 +0 -0
  41. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs/templates/readme.md.j2 +0 -0
  42. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs.egg-info/dependency_links.txt +0 -0
  43. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs.egg-info/entry_points.txt +0 -0
  44. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs.egg-info/requires.txt +0 -0
  45. {code2docs-0.1.6 → code2docs-0.2.1}/code2docs.egg-info/top_level.txt +0 -0
  46. {code2docs-0.1.6 → code2docs-0.2.1}/setup.cfg +0 -0
  47. {code2docs-0.1.6 → code2docs-0.2.1}/tests/test_analyzers.py +0 -0
  48. {code2docs-0.1.6 → code2docs-0.2.1}/tests/test_code2docs.py +0 -0
  49. {code2docs-0.1.6 → code2docs-0.2.1}/tests/test_config.py +0 -0
  50. {code2docs-0.1.6 → code2docs-0.2.1}/tests/test_formatters.py +0 -0
  51. {code2docs-0.1.6 → code2docs-0.2.1}/tests/test_generators.py +0 -0
  52. {code2docs-0.1.6 → code2docs-0.2.1}/tests/test_sync.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code2docs
3
- Version: 0.1.6
3
+ Version: 0.2.1
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.6-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.2.1-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
 
@@ -180,7 +180,7 @@ code2docs can update only specific sections of an existing README using markers:
180
180
  ```markdown
181
181
  <!-- code2docs:start --># code2docs
182
182
 
183
- ![version](https://img.shields.io/badge/version-0.1.6-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
183
+ ![version](https://img.shields.io/badge/version-0.2.1-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
184
184
  > **153** functions | **30** classes | **28** files | CC̄ = 0.0
185
185
 
186
186
  ## Installation
@@ -1,6 +1,6 @@
1
1
  # code2docs
2
2
 
3
- ![version](https://img.shields.io/badge/version-0.1.6-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.2.1-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
 
@@ -140,7 +140,7 @@ code2docs can update only specific sections of an existing README using markers:
140
140
  ```markdown
141
141
  <!-- code2docs:start --># code2docs
142
142
 
143
- ![version](https://img.shields.io/badge/version-0.1.6-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
143
+ ![version](https://img.shields.io/badge/version-0.2.1-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
144
144
  > **153** functions | **30** classes | **28** files | CC̄ = 0.0
145
145
 
146
146
  ## Installation
@@ -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.6"
8
+ __version__ = "0.2.1"
9
9
  __author__ = "Tom Sapletta"
10
10
 
11
11
  from .config import Code2DocsConfig
@@ -1,5 +1,7 @@
1
1
  """Dependency graph generator — Mermaid diagram from coupling matrix."""
2
2
 
3
+ import ast
4
+ from pathlib import Path
3
5
  from typing import Dict, List, Set, Tuple
4
6
 
5
7
  from code2llm.api import AnalysisResult, ModuleInfo
@@ -37,16 +39,42 @@ class DepGraphGenerator:
37
39
  return "\n".join(lines)
38
40
 
39
41
  def _collect_edges(self) -> List[Tuple[str, str]]:
40
- """Build directed edges from module imports."""
41
- edges: List[Tuple[str, str]] = []
42
+ """Build directed edges from module imports.
43
+
44
+ Uses ModuleInfo.imports when available, otherwise extracts
45
+ imports from the source file via AST.
46
+ """
47
+ edges: Set[Tuple[str, str]] = set()
42
48
  module_names = set(self.result.modules.keys())
43
49
 
44
50
  for mod_name, mod_info in self.result.modules.items():
45
- for imp in mod_info.imports:
51
+ imports = mod_info.imports
52
+ if not imports:
53
+ imports = self._extract_imports_from_file(mod_info.file)
54
+ for imp in imports:
46
55
  for other in module_names:
47
56
  if mod_name != other and self._import_matches(imp, other):
48
- edges.append((mod_name, other))
49
- return sorted(set(edges))
57
+ edges.add((mod_name, other))
58
+ return sorted(edges)
59
+
60
+ @staticmethod
61
+ def _extract_imports_from_file(file_path: str) -> List[str]:
62
+ """Parse source file AST to extract import targets."""
63
+ try:
64
+ source = Path(file_path).read_text(encoding="utf-8")
65
+ tree = ast.parse(source)
66
+ except Exception:
67
+ return []
68
+
69
+ imports: List[str] = []
70
+ for node in ast.walk(tree):
71
+ if isinstance(node, ast.Import):
72
+ for alias in node.names:
73
+ imports.append(alias.name)
74
+ elif isinstance(node, ast.ImportFrom):
75
+ if node.module:
76
+ imports.append(node.module)
77
+ return imports
50
78
 
51
79
  @staticmethod
52
80
  def _import_matches(imp: str, module: str) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code2docs
3
- Version: 0.1.6
3
+ Version: 0.2.1
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.6-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.2.1-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
 
@@ -180,7 +180,7 @@ code2docs can update only specific sections of an existing README using markers:
180
180
  ```markdown
181
181
  <!-- code2docs:start --># code2docs
182
182
 
183
- ![version](https://img.shields.io/badge/version-0.1.6-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
183
+ ![version](https://img.shields.io/badge/version-0.2.1-blue) ![python](https://img.shields.io/badge/python-%3E%3D3.9-blue) ![coverage](https://img.shields.io/badge/coverage-unknown-lightgrey) ![functions](https://img.shields.io/badge/functions-153-green)
184
184
  > **153** functions | **30** classes | **28** files | CC̄ = 0.0
185
185
 
186
186
  ## Installation
@@ -42,6 +42,7 @@ code2docs/templates/index.md.j2
42
42
  code2docs/templates/module_doc.md.j2
43
43
  code2docs/templates/readme.md.j2
44
44
  tests/test_analyzers.py
45
+ tests/test_cli.py
45
46
  tests/test_code2docs.py
46
47
  tests/test_config.py
47
48
  tests/test_formatters.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code2docs"
7
- version = "0.1.6"
7
+ version = "0.2.1"
8
8
  description = "Auto-generate and sync project documentation from source code analysis"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -0,0 +1,67 @@
1
+ """CLI smoke tests using Click's CliRunner."""
2
+
3
+ import tempfile
4
+ from pathlib import Path
5
+
6
+ from click.testing import CliRunner
7
+
8
+ from code2docs.cli import main
9
+
10
+
11
+ class TestCLI:
12
+ def setup_method(self):
13
+ self.runner = CliRunner()
14
+
15
+ def test_help(self):
16
+ result = self.runner.invoke(main, ["--help"])
17
+ assert result.exit_code == 0
18
+ assert "code2docs" in result.output
19
+ assert "generate" in result.output
20
+ assert "sync" in result.output
21
+ assert "init" in result.output
22
+
23
+ def test_generate_help(self):
24
+ result = self.runner.invoke(main, ["generate", "--help"])
25
+ assert result.exit_code == 0
26
+ assert "--readme-only" in result.output
27
+ assert "--dry-run" in result.output
28
+ assert "--verbose" in result.output
29
+
30
+ def test_sync_help(self):
31
+ result = self.runner.invoke(main, ["sync", "--help"])
32
+ assert result.exit_code == 0
33
+ assert "Synchronize" in result.output
34
+
35
+ def test_init_creates_config(self):
36
+ with tempfile.TemporaryDirectory() as tmpdir:
37
+ result = self.runner.invoke(main, ["init", tmpdir])
38
+ assert result.exit_code == 0
39
+ assert (Path(tmpdir) / "code2docs.yaml").exists()
40
+
41
+ def test_generate_dry_run(self):
42
+ result = self.runner.invoke(main, [".", "--dry-run"])
43
+ assert result.exit_code == 0
44
+ assert "code2docs" in result.output
45
+ assert "README.md" in result.output
46
+ assert "dry-run" in result.output
47
+ assert "Done!" in result.output
48
+
49
+ def test_readme_only_dry_run(self):
50
+ result = self.runner.invoke(main, [".", "--readme-only", "--dry-run"])
51
+ assert result.exit_code == 0
52
+ assert "README.md" in result.output
53
+ # Should NOT have docs/api since --readme-only
54
+ assert "docs/api" not in result.output
55
+
56
+ def test_default_group_routes_path(self):
57
+ """Ensure bare path argument is routed to generate."""
58
+ result = self.runner.invoke(main, [".", "--dry-run"])
59
+ assert result.exit_code == 0
60
+ assert "Done!" in result.output
61
+
62
+ def test_verbose(self):
63
+ result = self.runner.invoke(main, [".", "--verbose", "--dry-run"])
64
+ assert result.exit_code == 0
65
+ assert "Functions:" in result.output
66
+ assert "Classes:" in result.output
67
+ assert "Modules:" in result.output
File without changes
File without changes
File without changes
File without changes
File without changes