code2docs 3.0.34__tar.gz → 3.0.35__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-3.0.34 → code2docs-3.0.35}/PKG-INFO +9 -10
- {code2docs-3.0.34 → code2docs-3.0.35}/README.md +7 -5
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/__init__.py +1 -1
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/analyzers/endpoint_detector.py +32 -1
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/llm_helper.py +15 -2
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs.egg-info/PKG-INFO +9 -10
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs.egg-info/requires.txt +0 -2
- {code2docs-3.0.34 → code2docs-3.0.35}/pyproject.toml +8 -21
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_analyzers.py +14 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_llm_helper.py +24 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/LICENSE +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/__main__.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/analyzers/__init__.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/analyzers/dependency_scanner.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/analyzers/docstring_extractor.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/analyzers/markdown_validator.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/analyzers/project_scanner.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/base.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/cli.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/config.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/examples/advanced_usage.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/examples/quickstart.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/formatters/__init__.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/formatters/badges.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/formatters/markdown.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/formatters/toc.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/__init__.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/_registry_adapters.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/_source_links.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/api_changelog_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/api_reference_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/architecture_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/changelog_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/code2llm_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/config_docs_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/contributing_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/coverage_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/depgraph_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/examples_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/getting_started_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/mkdocs_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/module_docs_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/org_readme_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/generators/readme_gen.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/registry.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/sync/__init__.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/sync/differ.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/sync/updater.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/sync/watcher.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/templates/api_module.md.j2 +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/templates/architecture.md.j2 +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/templates/example_usage.py.j2 +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/templates/index.md.j2 +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/templates/module_doc.md.j2 +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs/templates/readme.md.j2 +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs.egg-info/SOURCES.txt +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs.egg-info/dependency_links.txt +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs.egg-info/entry_points.txt +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/code2docs.egg-info/top_level.txt +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/setup.cfg +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_cli.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_code2docs.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_config.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_formatters.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_generators.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_markdown_validator.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_registry.py +0 -0
- {code2docs-3.0.34 → code2docs-3.0.35}/tests/test_sync.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2docs
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.35
|
|
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
|
|
@@ -11,14 +11,13 @@ Keywords: documentation,auto-docs,readme-generator,api-reference,code-analysis,s
|
|
|
11
11
|
Classifier: Development Status :: 3 - Alpha
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Topic :: Software Development :: Documentation
|
|
20
19
|
Classifier: Topic :: Software Development :: Code Generators
|
|
21
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
22
21
|
Description-Content-Type: text/markdown
|
|
23
22
|
License-File: LICENSE
|
|
24
23
|
Requires-Dist: code2llm>=0.5.0
|
|
@@ -44,24 +43,24 @@ Requires-Dist: ruff>=0.1; extra == "dev"
|
|
|
44
43
|
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
45
44
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
46
45
|
Requires-Dist: twine>=5.0; extra == "dev"
|
|
47
|
-
Requires-Dist: goal>=2.1.0; extra == "dev"
|
|
48
46
|
Requires-Dist: costs>=0.1.20; extra == "dev"
|
|
49
|
-
Requires-Dist: pfix>=0.1.60; extra == "dev"
|
|
50
47
|
Provides-Extra: all
|
|
51
48
|
Requires-Dist: code2docs[git,llm,mkdocs,watch]; extra == "all"
|
|
52
49
|
Dynamic: license-file
|
|
53
50
|
|
|
54
51
|
## AI Cost Tracking
|
|
55
52
|
|
|
56
|
-
   
|
|
54
|
+
  
|
|
57
55
|
|
|
58
|
-
|
|
56
|
+
- 🤖 **LLM usage:** $5.3635 (99 commits)
|
|
57
|
+
- 👤 **Human dev:** ~$4589 (45.9h @ $100/h, 30min dedup)
|
|
59
58
|
|
|
60
|
-
Generated on 2026-
|
|
59
|
+
Generated on 2026-10-04 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
61
60
|
|
|
62
61
|
---
|
|
63
62
|
|
|
64
|
-
  
|
|
65
64
|
|
|
66
65
|
> Auto-generate and sync project documentation from source code analysis.
|
|
67
66
|
|
|
@@ -198,7 +197,7 @@ code2docs can update only specific sections of an existing README using markers:
|
|
|
198
197
|
```markdown
|
|
199
198
|
<!-- code2docs:start --># code2docs
|
|
200
199
|
|
|
201
|
-
   
|
|
202
201
|
> **276** functions | **57** classes | **51** files | CC̄ = 3.8
|
|
203
202
|
|
|
204
203
|
> Auto-generated project documentation from source code analysis.
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
## AI Cost Tracking
|
|
2
2
|
|
|
3
|
-
   
|
|
4
|
+
  
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
- 🤖 **LLM usage:** $5.3635 (99 commits)
|
|
7
|
+
- 👤 **Human dev:** ~$4589 (45.9h @ $100/h, 30min dedup)
|
|
6
8
|
|
|
7
|
-
Generated on 2026-
|
|
9
|
+
Generated on 2026-10-04 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
8
10
|
|
|
9
11
|
---
|
|
10
12
|
|
|
11
|
-
  
|
|
12
14
|
|
|
13
15
|
> Auto-generate and sync project documentation from source code analysis.
|
|
14
16
|
|
|
@@ -145,7 +147,7 @@ code2docs can update only specific sections of an existing README using markers:
|
|
|
145
147
|
```markdown
|
|
146
148
|
<!-- code2docs:start --># code2docs
|
|
147
149
|
|
|
148
|
-
   
|
|
149
151
|
> **276** functions | **57** classes | **51** files | CC̄ = 3.8
|
|
150
152
|
|
|
151
153
|
> Auto-generated project documentation from source code analysis.
|
|
@@ -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__ = "3.0.
|
|
8
|
+
__version__ = "3.0.35"
|
|
9
9
|
__author__ = "Tom Sapletta"
|
|
10
10
|
__all__ = ["Code2DocsConfig", "generate_readme", "generate_docs", "analyze_and_document"]
|
|
11
11
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Detect web framework endpoints (Flask, FastAPI, Django) from AST analysis."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
import re
|
|
4
5
|
from dataclasses import dataclass, field
|
|
5
6
|
from pathlib import Path
|
|
@@ -23,6 +24,36 @@ class Endpoint:
|
|
|
23
24
|
return_type: Optional[str] = None
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
# Directories never searched for Django urls.py: virtualenvs, vendored packages,
|
|
28
|
+
# VCS/worktree copies and build output. Walking them dominated runtime (~40s on
|
|
29
|
+
# a workspace with vendored site-packages). Any dot-directory is skipped too.
|
|
30
|
+
_SKIP_DIRS = frozenset(
|
|
31
|
+
{
|
|
32
|
+
"venv",
|
|
33
|
+
"env",
|
|
34
|
+
"node_modules",
|
|
35
|
+
"site-packages",
|
|
36
|
+
"__pycache__",
|
|
37
|
+
"dist",
|
|
38
|
+
"build",
|
|
39
|
+
"target",
|
|
40
|
+
"bower_components",
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _iter_urls_files(root: Path):
|
|
46
|
+
"""Yield ``urls.py`` files under *root*, pruning irrelevant directories."""
|
|
47
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
48
|
+
dirnames[:] = [
|
|
49
|
+
d
|
|
50
|
+
for d in dirnames
|
|
51
|
+
if d not in _SKIP_DIRS and not d.startswith(".") and not d.endswith(".egg-info")
|
|
52
|
+
]
|
|
53
|
+
if "urls.py" in filenames:
|
|
54
|
+
yield Path(dirpath) / "urls.py"
|
|
55
|
+
|
|
56
|
+
|
|
26
57
|
class EndpointDetector:
|
|
27
58
|
"""Detects web endpoints from decorator patterns in source code."""
|
|
28
59
|
|
|
@@ -91,7 +122,7 @@ class EndpointDetector:
|
|
|
91
122
|
endpoints: List[Endpoint] = []
|
|
92
123
|
project = Path(project_path)
|
|
93
124
|
|
|
94
|
-
for urls_file in project
|
|
125
|
+
for urls_file in _iter_urls_files(project):
|
|
95
126
|
try:
|
|
96
127
|
source = urls_file.read_text(encoding="utf-8")
|
|
97
128
|
for match in self.DJANGO_URL_PATTERN.finditer(source):
|
|
@@ -4,6 +4,7 @@ If litellm is not installed or LLM is not configured, all methods return None
|
|
|
4
4
|
and generators fall back to algorithm-based template output.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import importlib.util
|
|
7
8
|
import logging
|
|
8
9
|
from typing import Optional
|
|
9
10
|
|
|
@@ -29,6 +30,18 @@ def _get_litellm():
|
|
|
29
30
|
return _litellm if _litellm is not False else None
|
|
30
31
|
|
|
31
32
|
|
|
33
|
+
def _litellm_installed() -> bool:
|
|
34
|
+
"""Cheap availability check: locate litellm without importing it.
|
|
35
|
+
|
|
36
|
+
Importing litellm costs ~10s, so it must only happen when a completion is
|
|
37
|
+
actually requested (see ``_get_litellm`` in ``LLMHelper.complete``).
|
|
38
|
+
"""
|
|
39
|
+
try:
|
|
40
|
+
return importlib.util.find_spec("litellm") is not None
|
|
41
|
+
except (ImportError, ValueError):
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
|
|
32
45
|
class LLMHelper:
|
|
33
46
|
"""Thin wrapper around litellm for documentation generation.
|
|
34
47
|
|
|
@@ -45,7 +58,7 @@ class LLMHelper:
|
|
|
45
58
|
"""Check if LLM is configured and litellm is installed."""
|
|
46
59
|
if self._available is None:
|
|
47
60
|
self._available = (
|
|
48
|
-
self.config.enabled and bool(self.config.model) and
|
|
61
|
+
self.config.enabled and bool(self.config.model) and _litellm_installed()
|
|
49
62
|
)
|
|
50
63
|
if self._available:
|
|
51
64
|
logger.info("LLM enabled: model=%s", self.config.model)
|
|
@@ -54,7 +67,7 @@ class LLMHelper:
|
|
|
54
67
|
"LLM disabled (enabled=%s, model=%s, litellm=%s)",
|
|
55
68
|
self.config.enabled,
|
|
56
69
|
bool(self.config.model),
|
|
57
|
-
|
|
70
|
+
_litellm_installed(),
|
|
58
71
|
)
|
|
59
72
|
return self._available
|
|
60
73
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2docs
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.35
|
|
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
|
|
@@ -11,14 +11,13 @@ Keywords: documentation,auto-docs,readme-generator,api-reference,code-analysis,s
|
|
|
11
11
|
Classifier: Development Status :: 3 - Alpha
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Topic :: Software Development :: Documentation
|
|
20
19
|
Classifier: Topic :: Software Development :: Code Generators
|
|
21
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
22
21
|
Description-Content-Type: text/markdown
|
|
23
22
|
License-File: LICENSE
|
|
24
23
|
Requires-Dist: code2llm>=0.5.0
|
|
@@ -44,24 +43,24 @@ Requires-Dist: ruff>=0.1; extra == "dev"
|
|
|
44
43
|
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
45
44
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
46
45
|
Requires-Dist: twine>=5.0; extra == "dev"
|
|
47
|
-
Requires-Dist: goal>=2.1.0; extra == "dev"
|
|
48
46
|
Requires-Dist: costs>=0.1.20; extra == "dev"
|
|
49
|
-
Requires-Dist: pfix>=0.1.60; extra == "dev"
|
|
50
47
|
Provides-Extra: all
|
|
51
48
|
Requires-Dist: code2docs[git,llm,mkdocs,watch]; extra == "all"
|
|
52
49
|
Dynamic: license-file
|
|
53
50
|
|
|
54
51
|
## AI Cost Tracking
|
|
55
52
|
|
|
56
|
-
   
|
|
54
|
+
  
|
|
57
55
|
|
|
58
|
-
|
|
56
|
+
- 🤖 **LLM usage:** $5.3635 (99 commits)
|
|
57
|
+
- 👤 **Human dev:** ~$4589 (45.9h @ $100/h, 30min dedup)
|
|
59
58
|
|
|
60
|
-
Generated on 2026-
|
|
59
|
+
Generated on 2026-10-04 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
61
60
|
|
|
62
61
|
---
|
|
63
62
|
|
|
64
|
-
  
|
|
65
64
|
|
|
66
65
|
> Auto-generate and sync project documentation from source code analysis.
|
|
67
66
|
|
|
@@ -198,7 +197,7 @@ code2docs can update only specific sections of an existing README using markers:
|
|
|
198
197
|
```markdown
|
|
199
198
|
<!-- code2docs:start --># code2docs
|
|
200
199
|
|
|
201
|
-
   
|
|
202
201
|
> **276** functions | **57** classes | **51** files | CC̄ = 3.8
|
|
203
202
|
|
|
204
203
|
> Auto-generated project documentation from source code analysis.
|
|
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code2docs"
|
|
7
|
-
version = "3.0.
|
|
7
|
+
version = "3.0.35"
|
|
8
8
|
description = "Auto-generate and sync project documentation from source code analysis"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
authors = [
|
|
13
13
|
{name = "Tom Sapletta", email = "tom@sapletta.com"},
|
|
@@ -25,7 +25,6 @@ classifiers = [
|
|
|
25
25
|
"Development Status :: 3 - Alpha",
|
|
26
26
|
"Intended Audience :: Developers",
|
|
27
27
|
"Programming Language :: Python :: 3",
|
|
28
|
-
"Programming Language :: Python :: 3.9",
|
|
29
28
|
"Programming Language :: Python :: 3.10",
|
|
30
29
|
"Programming Language :: Python :: 3.11",
|
|
31
30
|
"Programming Language :: Python :: 3.12",
|
|
@@ -54,9 +53,7 @@ dev = [
|
|
|
54
53
|
"mypy>=1.0",
|
|
55
54
|
"build>=1.0",
|
|
56
55
|
"twine>=5.0",
|
|
57
|
-
"goal>=2.1.0",
|
|
58
56
|
"costs>=0.1.20",
|
|
59
|
-
"pfix>=0.1.60",
|
|
60
57
|
]
|
|
61
58
|
all = ["code2docs[llm,git,watch,mkdocs]"]
|
|
62
59
|
|
|
@@ -90,22 +87,6 @@ include = ["code2docs*"]
|
|
|
90
87
|
[tool.setuptools.package-data]
|
|
91
88
|
code2docs = ["templates/*.j2"]
|
|
92
89
|
|
|
93
|
-
[tool.pfix]
|
|
94
|
-
# Self-healing Python configuration
|
|
95
|
-
model = "openrouter/qwen/qwen3-coder-next"
|
|
96
|
-
auto_apply = true
|
|
97
|
-
auto_install_deps = true
|
|
98
|
-
auto_restart = false
|
|
99
|
-
max_retries = 3
|
|
100
|
-
create_backups = false
|
|
101
|
-
git_auto_commit = false
|
|
102
|
-
|
|
103
|
-
[tool.pfix.runtime_todo]
|
|
104
|
-
enabled = true
|
|
105
|
-
todo_file = "TODO.md"
|
|
106
|
-
min_severity = "low"
|
|
107
|
-
deduplicate = true
|
|
108
|
-
|
|
109
90
|
[tool.costs]
|
|
110
91
|
# AI Cost tracking configuration
|
|
111
92
|
badge = true
|
|
@@ -118,3 +99,9 @@ max_commits = 500
|
|
|
118
99
|
|
|
119
100
|
# Cost thresholds for badge colors (USD)
|
|
120
101
|
badge_color_thresholds = { low = 1.0, medium = 5.0, high = 10.0, critical = 50.0 }
|
|
102
|
+
|
|
103
|
+
[tool.uv.dependency-groups.automation]
|
|
104
|
+
requires-python = ">=3.12"
|
|
105
|
+
|
|
106
|
+
[dependency-groups]
|
|
107
|
+
automation = ["goal>=2.1.302"]
|
|
@@ -136,3 +136,17 @@ class TestEndpointDetector:
|
|
|
136
136
|
)
|
|
137
137
|
ep = detector._parse_decorator(func.decorators[0], func)
|
|
138
138
|
assert ep is None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_endpoint_detector_skips_vendored_and_hidden_dirs(tmp_path):
|
|
142
|
+
from code2docs.analyzers.endpoint_detector import EndpointDetector
|
|
143
|
+
|
|
144
|
+
(tmp_path / "app").mkdir()
|
|
145
|
+
(tmp_path / "app" / "urls.py").write_text("urlpatterns = [path('real/', v)]\n")
|
|
146
|
+
for skipped in (".subactor/lib/site-packages/x", "venv/lib", "node_modules/y", ".worktrees/t1"):
|
|
147
|
+
d = tmp_path / skipped
|
|
148
|
+
d.mkdir(parents=True)
|
|
149
|
+
(d / "urls.py").write_text("urlpatterns = [path('vendored/', v)]\n")
|
|
150
|
+
|
|
151
|
+
paths = [e.path for e in EndpointDetector()._scan_django_urls(str(tmp_path))]
|
|
152
|
+
assert paths == ["real/"]
|
|
@@ -270,3 +270,27 @@ class TestGeneratorFallback:
|
|
|
270
270
|
content = gen.generate()
|
|
271
271
|
assert "Getting Started" in content
|
|
272
272
|
assert "Installation" in content
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# ── Performance regression tests ─────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class TestLazyLitellmImport:
|
|
279
|
+
"""Availability checks must not import litellm (~10s)."""
|
|
280
|
+
|
|
281
|
+
def test_disabled_helper_never_imports_litellm(self):
|
|
282
|
+
from code2docs import llm_helper
|
|
283
|
+
from code2docs.config import LLMConfig
|
|
284
|
+
|
|
285
|
+
with patch("code2docs.llm_helper._get_litellm") as get_litellm:
|
|
286
|
+
assert LLMHelper(LLMConfig(enabled=False)).available is False
|
|
287
|
+
get_litellm.assert_not_called()
|
|
288
|
+
|
|
289
|
+
def test_enabled_availability_uses_find_spec_not_import(self):
|
|
290
|
+
from code2docs.config import LLMConfig
|
|
291
|
+
|
|
292
|
+
with patch("code2docs.llm_helper._litellm_installed", return_value=True), patch(
|
|
293
|
+
"code2docs.llm_helper._get_litellm"
|
|
294
|
+
) as get_litellm:
|
|
295
|
+
assert LLMHelper(LLMConfig(enabled=True, model="x")).available is True
|
|
296
|
+
get_litellm.assert_not_called()
|
|
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
|
|
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
|