pycodecommenter 2.2.0__tar.gz → 2.3.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.
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.well-known/ai-plugin.json +1 -1
- pycodecommenter-2.3.0/CHANGELOG.md +167 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/CITATION.cff +2 -2
- pycodecommenter-2.3.0/Future Work/More future work prompt.md +82 -0
- pycodecommenter-2.3.0/Future Work/More future work.md +208 -0
- {pycodecommenter-2.2.0/pycodecommenter.egg-info → pycodecommenter-2.3.0}/PKG-INFO +11 -12
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/__init__.py +1 -1
- pycodecommenter-2.3.0/PyCodeCommenter/cli.py +297 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/commenter.py +119 -50
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/coverage.py +35 -3
- pycodecommenter-2.3.0/PyCodeCommenter/docstring_parser.py +215 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/inference.py +20 -4
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/validator.py +15 -6
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/README.md +8 -9
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/index.md +4 -4
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/llms.txt +3 -3
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0/pycodecommenter.egg-info}/PKG-INFO +11 -12
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/SOURCES.txt +3 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/requires.txt +1 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pyproject.toml +3 -4
- pycodecommenter-2.3.0/test_docstring_parser.py +120 -0
- pycodecommenter-2.3.0/test_edge_cases.py +334 -0
- pycodecommenter-2.2.0/CHANGELOG.md +0 -63
- pycodecommenter-2.2.0/PyCodeCommenter/cli.py +0 -130
- pycodecommenter-2.2.0/PyCodeCommenter/docstring_parser.py +0 -121
- pycodecommenter-2.2.0/test_edge_cases.py +0 -58
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.github/workflows/docs.yml +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.github/workflows/publish.yml +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.gitignore +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/CONTRIBUTING.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/Future Release WorkPlan.txt +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/Vulnerabilties.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/v2.1.0 /342/200/224 Remaining Items (dry-run, backup, config loader, test rewrite).txt" +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/v2.2.0 /342/200/224 Accuracy & Output.txt" +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/v3.0.0 /342/200/224 Safe, Configurable, Extensible.txt" +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/v3.1.0 /342/200/224 Integrations.txt" +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/LICENSE +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/config.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/parameter_descriptions.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/templates.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/type_analyzer.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/conftest.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/assets/.gitkeep +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/changelog.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/cli-reference.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/configuration.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/contributing.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/docstring-styles.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/faq.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/getting-started.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/javascripts/custom.js +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/python-api.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/recipes.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/robots.txt +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/stylesheets/extra.css +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/validation-checks.md +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/basic_usage.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/ci_integration.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/coverage_example.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/validation_example.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/main.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/mkdocs.yml +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/dependency_links.txt +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/entry_points.txt +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/top_level.txt +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/scratch/test_infer.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/scratch/test_mixed_returns.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/scratch/test_unicode.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/setup.cfg +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_backwards_compatibility.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_basic_validation.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_coverage.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_integration.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_modern.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_type_analyzer.py +0 -0
- {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_validation.py +0 -0
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"repository": "https://github.com/AmosQuety/PyCodeCommenter",
|
|
18
18
|
"pypi": "https://pypi.org/project/pycodecommenter/",
|
|
19
19
|
"install_command": "pip install pycodecommenter",
|
|
20
|
-
"version": "2.
|
|
20
|
+
"version": "2.3.0",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"author": "Nabasa Amos (Amos Quety)"
|
|
23
23
|
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to PyCodeCommenter will be documented in this file.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
|
+
|
|
6
|
+
## [2.3.0] - 2026-08-22
|
|
7
|
+
|
|
8
|
+
Follow-up work from an internal engineering audit (`Future Work/Vulnerabilties.md`),
|
|
9
|
+
plus a documentation-fidelity pass (Phase 6) found during pre-release review.
|
|
10
|
+
|
|
11
|
+
### Breaking Changes
|
|
12
|
+
- **Minimum Python version raised from 3.8 to 3.9.** `pyproject.toml`'s
|
|
13
|
+
`requires-python` is now `>=3.9`; the `Programming Language :: Python :: 3.8`
|
|
14
|
+
classifier was removed. This was forced by the new `libcst` dependency (see
|
|
15
|
+
below), whose current release requires Python >=3.9. **Any user still on
|
|
16
|
+
Python 3.8 will no longer be able to install new releases of this package.**
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- **New runtime dependency: `libcst>=1.1`.** `get_patched_code()` (the code
|
|
20
|
+
that inserts/updates generated docstrings) was rewritten to apply edits via
|
|
21
|
+
libcst's concrete syntax tree instead of line-number arithmetic on raw
|
|
22
|
+
source text. This is a hard dependency, not optional — installing
|
|
23
|
+
`pycodecommenter` now also installs `libcst`.
|
|
24
|
+
- `generate` and `validate` CLI commands now accept a directory as well as a
|
|
25
|
+
single file, recursively collecting `.py` files (mirroring `coverage`'s
|
|
26
|
+
existing directory support).
|
|
27
|
+
- `--fail-below THRESHOLD` flag on the `coverage` CLI command; exits 1 when
|
|
28
|
+
coverage is below the threshold.
|
|
29
|
+
- `.pycodecommenter.yaml` config is now actually read by the CLI: its
|
|
30
|
+
top-level `exclude` list defaults `-e/--exclude` on all three subcommands,
|
|
31
|
+
and `coverage.threshold` defaults `--fail-below`. Both remain overridable
|
|
32
|
+
by explicit CLI flags. (Previously `config.py` existed but nothing called it.)
|
|
33
|
+
- NumPy-style docstrings (`Parameters`/`Returns`/`Raises` with dash-underlined
|
|
34
|
+
headers) are now parsed as input, alongside Google and Sphinx style.
|
|
35
|
+
Sphinx-style input also gained `:type name: TYPE` support.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- **One-line function/class definitions could corrupt the file when patched.**
|
|
39
|
+
`def foo(): return 1` (body on the same physical line as the `def`) would
|
|
40
|
+
have its generated docstring inserted *before* the `def` line instead of
|
|
41
|
+
inside the function, producing a `SyntaxError`. Every one-liner shape
|
|
42
|
+
reproduced this: `pass`, `return`, multiple `;`-separated statements,
|
|
43
|
+
`async def`, and one-line `class` bodies. Fixed by the libcst rewrite above,
|
|
44
|
+
which converts a one-liner body to a proper indented block before inserting.
|
|
45
|
+
(This is a different, narrower bug than the "multi-line signature
|
|
46
|
+
corruption" originally suspected from the audit — see Notes below.)
|
|
47
|
+
- `PyCodeCommenter.validate()` now passes the real file path to the validator
|
|
48
|
+
instead of a hardcoded `None`, so validation report locations show the
|
|
49
|
+
actual file (e.g. `src/api.py:12:my_func`) instead of `code:12:my_func`.
|
|
50
|
+
- `PyCodeCommenter.check_coverage()` now uses the real file path instead of
|
|
51
|
+
the leaked `"<string>"` placeholder.
|
|
52
|
+
- `docstring_parser.py`: multi-line `Args:` parameter descriptions in an
|
|
53
|
+
*existing* docstring being re-parsed were silently truncated unless the
|
|
54
|
+
continuation line was indented by exactly 8 spaces. Any other indentation
|
|
55
|
+
(including 4 spaces — the same indent this project's own generator uses)
|
|
56
|
+
lost the continuation text on merge. Now any non-blank continuation line is
|
|
57
|
+
recognized regardless of indentation depth.
|
|
58
|
+
- `generate`/`validate` directory mode's default exclude list
|
|
59
|
+
(`__pycache__`, `.git`, `.venv`, `venv`, `env`, `.eggs`) missed common
|
|
60
|
+
vendor/build directories and used raw substring matching, causing two real
|
|
61
|
+
problems: `environment_config.py` was silently skipped (`"env"` is a
|
|
62
|
+
substring of `"environment"`), and files inside `.tox/.../site-packages/`
|
|
63
|
+
were *not* skipped — with `generate --inplace`, writing generated
|
|
64
|
+
docstrings into vendored third-party source. Expanded the default list
|
|
65
|
+
(added `.tox`, `.nox`, `__pypackages__`, `site-packages`, `build`, `dist`,
|
|
66
|
+
`.egg-info`, `.mypy_cache`, `.pytest_cache`, `node_modules`) and switched
|
|
67
|
+
to exact-path-component matching. `coverage`'s directory mode had the same
|
|
68
|
+
two problems independently (a separate, duplicated exclude list) and is
|
|
69
|
+
fixed the same way, plus a related bug: passing any custom `--exclude`
|
|
70
|
+
pattern previously replaced its default list entirely rather than adding
|
|
71
|
+
to it, silently losing `.venv`/`.git` protection.
|
|
72
|
+
- A parameter's documented type (e.g. `x (int):`) was silently downgraded to
|
|
73
|
+
`x (any):` on regeneration whenever static type inference had nothing to
|
|
74
|
+
work with (no annotation on the parameter) — the type was parsed out of
|
|
75
|
+
the existing docstring but never stored or consulted. A real static
|
|
76
|
+
annotation still always wins; the docstring-parsed type is now used as a
|
|
77
|
+
fallback instead of being discarded.
|
|
78
|
+
- An existing NumPy-style docstring was not recognized as such, so its
|
|
79
|
+
entire body was treated as free-text and a fresh, auto-generated
|
|
80
|
+
Google-style `Args:`/`Returns:` section was appended underneath it —
|
|
81
|
+
documenting the same parameter twice, in two styles, in one docstring.
|
|
82
|
+
- Generated filler text for dunder methods (e.g. `__init__`) rendered with
|
|
83
|
+
broken spacing — `"Original of the init ."` — because
|
|
84
|
+
`name.replace('_', ' ')` turns every underscore into a space, including
|
|
85
|
+
the leading/trailing pair(s) dunder names have.
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
- `ValidationStats.infos` renamed to `.info` (matches the existing `"info"`
|
|
89
|
+
key in JSON/markdown output). `.infos` remains available as a
|
|
90
|
+
backward-compatible property alias.
|
|
91
|
+
|
|
92
|
+
### Notes
|
|
93
|
+
- Two "CRITICAL" bugs originally suspected from the audit — corruption on
|
|
94
|
+
multi-line function signatures, and a line-shift bug when patching multiple
|
|
95
|
+
functions in one file — were investigated and do not reproduce against this
|
|
96
|
+
version or the pre-libcst version; both were verified directly against the
|
|
97
|
+
audit's own examples plus additional stress tests. No code changes were
|
|
98
|
+
made for either.
|
|
99
|
+
- A third suspected bug — `ast.walk()` double-counting nested
|
|
100
|
+
functions/classes in `validate_all()`'s stats — also does not reproduce;
|
|
101
|
+
`ast.walk()` visits every node exactly once regardless of nesting depth.
|
|
102
|
+
`validator.py`'s counting logic is unchanged.
|
|
103
|
+
- PEP 604 union rendering (`int | str` currently renders as `Union[int, str]`
|
|
104
|
+
in generated docstrings, per `type_analyzer.py`) was identified as a real,
|
|
105
|
+
minor issue but deliberately deferred: fixing it breaks
|
|
106
|
+
`test_type_analyzer.py::test_union_annotation`, which asserts the old
|
|
107
|
+
`Union[...]` output, and no test-file changes were in scope for that part
|
|
108
|
+
of the work.
|
|
109
|
+
|
|
110
|
+
## [2.2.0] - 2026-07-12
|
|
111
|
+
|
|
112
|
+
### Added
|
|
113
|
+
- **Decorator-aware validation** — `@property` setter and deleter variants no longer produce false-positive
|
|
114
|
+
"missing Returns section" warnings. `@classmethod` (`cls`) and `@staticmethod` were verified already correct.
|
|
115
|
+
- **`--output-format json`** flag on both `validate` and `coverage` subcommands. Prints machine-readable
|
|
116
|
+
JSON to stdout; text output is completely unchanged.
|
|
117
|
+
- **`ValidationReport.to_dict()`** updated to spec-compliant shape: `stats.total`, `stats.info`,
|
|
118
|
+
`stats.coverage_percentage`; issues now include `line` (integer), `severity` (uppercase), `check`, `message`.
|
|
119
|
+
- **`_has_raises_section()` helper** in `validator.py` — recognises `Raises:` (Google), `Raises\n`
|
|
120
|
+
(bare header), and `:raises ` (Sphinx, trailing space prevents false matches).
|
|
121
|
+
- **`llms.txt`** file at repo root — AI agent and LLM crawler discovery file.
|
|
122
|
+
- **SEO/AEO optimisation** — keyword-rich README, PyPI classifiers/keywords, per-page meta tags on all
|
|
123
|
+
doc pages, JSON-LD `SoftwareApplication` schema on docs homepage.
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
- `test_validation.py` rewritten from script-style to proper pytest (17 tests, all pass).
|
|
127
|
+
- `pyproject.toml` keywords expanded to 20 terms; classifiers expanded with `Code Generators`,
|
|
128
|
+
`Libraries :: Python Modules`, `Environment :: Console`, `Operating System :: OS Independent`.
|
|
129
|
+
- `mkdocs.yml` enriched with `site_author`, explicit `language: en`, `navigation.indexes`,
|
|
130
|
+
`search.share`, `toc.follow`, and `meta` markdown extension for per-page SEO tags.
|
|
131
|
+
|
|
132
|
+
## [2.0.0] - 2026-01-25
|
|
133
|
+
|
|
134
|
+
### Major Release - Complete Rewrite
|
|
135
|
+
|
|
136
|
+
#### Added
|
|
137
|
+
- **Comprehensive Validation System** - 6 types of documentation checks
|
|
138
|
+
- **Coverage Analysis** - Project-wide documentation metrics
|
|
139
|
+
- **Modern Type Support** - PEP 604 unions, PEP 585 generics
|
|
140
|
+
- **Async Function Support** - Full support for `async def`
|
|
141
|
+
- **Multiple Export Formats** - JSON, Markdown, console output
|
|
142
|
+
- **Smart Docstring Parsing** - Preserves existing documentation
|
|
143
|
+
- **Structured AST Traversal** - NodeVisitor pattern for reliability
|
|
144
|
+
- **Professional Reporting** - Actionable error messages with suggestions
|
|
145
|
+
- **CI/CD Ready** - Easy integration with pipelines
|
|
146
|
+
|
|
147
|
+
#### Changed
|
|
148
|
+
- Replaced basic type inference with comprehensive `TypeAnalyzer`
|
|
149
|
+
- Improved docstring generation with better templates
|
|
150
|
+
- Enhanced error handling with proper logging
|
|
151
|
+
- Better handling of edge cases and malformed code
|
|
152
|
+
|
|
153
|
+
#### Fixed
|
|
154
|
+
- Duplicate `_infer_type` methods consolidated
|
|
155
|
+
- Brittle patching logic made robust
|
|
156
|
+
- Import resolution issues
|
|
157
|
+
- Unicode/encoding handling
|
|
158
|
+
|
|
159
|
+
#### Breaking Changes
|
|
160
|
+
- Minimum Python version: 3.8+
|
|
161
|
+
- Some internal APIs changed (public API remains compatible)
|
|
162
|
+
|
|
163
|
+
## [1.0.0] - Earlier Version
|
|
164
|
+
|
|
165
|
+
- Basic docstring generation
|
|
166
|
+
- Template-based descriptions
|
|
167
|
+
- File and string input support
|
|
@@ -14,8 +14,8 @@ authors:
|
|
|
14
14
|
email: amosnabasa4@gmail.com
|
|
15
15
|
website: https://nabasa-amos.netlify.app
|
|
16
16
|
orcid: ""
|
|
17
|
-
version: 2.
|
|
18
|
-
date-released: "2026-
|
|
17
|
+
version: 2.3.0
|
|
18
|
+
date-released: "2026-08-22"
|
|
19
19
|
license: MIT
|
|
20
20
|
repository-code: https://github.com/AmosQuety/PyCodeCommenter
|
|
21
21
|
url: https://amosquety.github.io/PyCodeCommenter/
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
You have a full engineering audit attached @More future work.md. This is a
|
|
2
|
+
multi-phase task with HARD STOPS between phases. You are not permitted to
|
|
3
|
+
combine phases, skip ahead, or make architecture decisions on my behalf,
|
|
4
|
+
even if the next step seems obvious.
|
|
5
|
+
|
|
6
|
+
GLOBAL RULES (apply to every phase):
|
|
7
|
+
- Work on a new git branch (e.g. `fix/audit-phaseN`). Do not commit to main.
|
|
8
|
+
- Each phase lists the EXACT files you are allowed to modify. Do not touch
|
|
9
|
+
any other file. If you believe another file must change to complete the
|
|
10
|
+
phase, STOP and tell me why instead of doing it.
|
|
11
|
+
- At the end of each phase, paste the FULL, UNTRUNCATED output of:
|
|
12
|
+
git diff --stat
|
|
13
|
+
git diff
|
|
14
|
+
python -m pytest -v
|
|
15
|
+
Do not summarize test results in prose ("37 passed") instead of pasting
|
|
16
|
+
the actual output. I want to see the real terminal output.
|
|
17
|
+
- After posting the above, write exactly: "PHASE N COMPLETE — WAITING FOR
|
|
18
|
+
APPROVAL" and STOP. Do not start the next phase in the same response,
|
|
19
|
+
even partially. Do not pre-write code for the next phase "for
|
|
20
|
+
efficiency."
|
|
21
|
+
- If completing a phase requires a design decision not specified below
|
|
22
|
+
(e.g. which library to use, which of two valid approaches to take),
|
|
23
|
+
STOP and ask me. Do not pick one yourself and proceed. A bracketed note
|
|
24
|
+
like "[we'll decide together]" means you must ask a direct question and
|
|
25
|
+
wait — it is not permission to choose.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
PHASE 1 — Trivial fixes (files: commenter.py, validator.py, type_analyzer.py)
|
|
30
|
+
- Fix PyCodeCommenter.validate() to pass self.file_path instead of None
|
|
31
|
+
- Fix check_coverage() to use the real file path instead of "<string>"
|
|
32
|
+
- Rename `infos` -> `info` consistently (backward-compatible alias is fine)
|
|
33
|
+
- Fix PEP 604 rendering: `X | Y` instead of `Union[X, Y]`
|
|
34
|
+
Do NOT touch get_patched_code() in this phase.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
PHASE 2 — Regression tests ONLY (files: test_edge_cases.py, and any new
|
|
39
|
+
test file you create — NO source files under PyCodeCommenter/ may change)
|
|
40
|
+
- Write a test that reproduces the multi-line signature corruption bug
|
|
41
|
+
(Question 2, first CRITICAL issue in the audit)
|
|
42
|
+
- Write a test that reproduces the line-shift insertion bug
|
|
43
|
+
- Run the tests and paste output PROVING they fail against the current
|
|
44
|
+
(unfixed) source code. A test that passes at the end of this phase is a
|
|
45
|
+
FAILURE of this phase — it means either the test is wrong or you fixed
|
|
46
|
+
the bug early, both of which are not allowed here.
|
|
47
|
+
- Do not modify commenter.py, validator.py, or type_analyzer.py in this
|
|
48
|
+
phase under any circumstance.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
PHASE 3 — Fix the patcher (BLOCKED until I respond to a question)
|
|
53
|
+
Before writing any code in this phase, ask me directly: "Should I use
|
|
54
|
+
libcst, or the ast.unparse() fallback?" and list, in your own words, the
|
|
55
|
+
tradeoffs of each — specifically including: does this approach preserve
|
|
56
|
+
comments in the source file? Does it preserve formatting/quote style?
|
|
57
|
+
What new dependency (if any) does it add?
|
|
58
|
+
Wait for my answer before writing any implementation code.
|
|
59
|
+
Once I've answered:
|
|
60
|
+
- Implement the chosen approach in get_patched_code() only
|
|
61
|
+
- Make the Phase 2 tests pass
|
|
62
|
+
- Add a NEW test that checks whether comments in the source file survive
|
|
63
|
+
patching, and tell me honestly whether they do or don't
|
|
64
|
+
- Confirm no other existing tests regress
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
PHASE 4 (files: cli.py, config.py)
|
|
69
|
+
- Add directory support to `validate` and `generate` CLI commands
|
|
70
|
+
- Add --fail-below to coverage CLI
|
|
71
|
+
- Wire load_config() into cli.py
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
PHASE 5 (files: validator.py, docstring_parser.py)
|
|
76
|
+
- Fix ast.walk() double-counting nested functions
|
|
77
|
+
- Fix hardcoded 8-space continuation-line parsing
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
Begin with Phase 1 only. Stop after Phase 1 and wait for my explicit
|
|
82
|
+
approval before starting Phase 2.
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# 🎯 Feature Improvement: Recursive Directory Support with Smart File Filtering
|
|
2
|
+
|
|
3
|
+
## Current Behavior
|
|
4
|
+
Currently, **PyCodeCommenter** is limited by the following constraints:
|
|
5
|
+
* **Single File Support Only:** Accepts only individual file paths.
|
|
6
|
+
* **Error Prone:** Fails with `[Errno 21] Is a directory` when passed a folder.
|
|
7
|
+
* **No Recursion:** Cannot traverse nested directory structures.
|
|
8
|
+
* **Manual Effort:** Users must manually exclude non-code files, virtual environments, and configuration folders.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Proposed Enhancement
|
|
13
|
+
### Problem Statement
|
|
14
|
+
PyCodeCommenter is impractical for real-world projects with multiple files and complex folder structures. Users are forced to write external shell scripts or manually loop through files. Furthermore, there is no native way to ignore clutter like `.venv`, `__pycache__`, or `.git` directories.
|
|
15
|
+
|
|
16
|
+
### Proposed Solution
|
|
17
|
+
Add native support for directory paths with the following capabilities:
|
|
18
|
+
1. **Recursive Processing:** Automatically find all Python files within a tree.
|
|
19
|
+
2. **Intelligent Filtering:** Automatically skip non-code files and common environment folders.
|
|
20
|
+
3. **Custom Exclusions:** Respect `exclude` patterns defined in a configuration file.
|
|
21
|
+
4. **Rich Feedback:** Provide a progress UI and a detailed summary report.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Implementation Details
|
|
26
|
+
|
|
27
|
+
### 1. Path Detection & File Collection
|
|
28
|
+
We will use `pathlib` for robust path handling and `os.walk` for traversal.
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
import os
|
|
33
|
+
|
|
34
|
+
# Default patterns to always skip
|
|
35
|
+
DEFAULT_IGNORE_PATTERNS = {
|
|
36
|
+
'.venv', 'venv', 'env', 'ENV', 'virtualenv',
|
|
37
|
+
'__pycache__', '*.pyc', '*.pyo', '*.pyd',
|
|
38
|
+
'.git', '.svn', '.hg',
|
|
39
|
+
'.vscode', '.idea', '.pycharm',
|
|
40
|
+
'build', 'dist', '.eggs', '*.egg-info',
|
|
41
|
+
'node_modules', 'package-lock.json', 'yarn.lock',
|
|
42
|
+
'.DS_Store', 'Thumbs.db',
|
|
43
|
+
'*.config', '*.ini', '*.toml', '*.yaml', '*.yml',
|
|
44
|
+
'*.json', '*.xml', '*.cfg',
|
|
45
|
+
'docs', '*.md', '*.rst', '*.txt',
|
|
46
|
+
'tests', 'test_*', '*_test.py',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
def should_skip_path(path, exclude_patterns=None):
|
|
50
|
+
"""Determine if a path should be skipped based on defaults and custom patterns."""
|
|
51
|
+
path_parts = Path(path).parts
|
|
52
|
+
|
|
53
|
+
# Check default patterns
|
|
54
|
+
for pattern in DEFAULT_IGNORE_PATTERNS:
|
|
55
|
+
if pattern.startswith('*.'):
|
|
56
|
+
if Path(path).suffix == pattern[1:]:
|
|
57
|
+
return True
|
|
58
|
+
elif pattern in path_parts:
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
# Check custom exclude patterns from config
|
|
62
|
+
if exclude_patterns:
|
|
63
|
+
for pattern in exclude_patterns:
|
|
64
|
+
if pattern.startswith('*.'):
|
|
65
|
+
if Path(path).suffix == pattern[1:]: return True
|
|
66
|
+
elif pattern.startswith('**/') and pattern[3:] in str(path):
|
|
67
|
+
return True
|
|
68
|
+
elif pattern in path_parts:
|
|
69
|
+
return True
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
def collect_py_files(path, exclude_patterns=None):
|
|
73
|
+
"""Recursively collect Python files, skipping ignored directories."""
|
|
74
|
+
if os.path.isfile(path):
|
|
75
|
+
return [path] if path.endswith('.py') else []
|
|
76
|
+
|
|
77
|
+
py_files = []
|
|
78
|
+
for root, dirs, files in os.walk(path):
|
|
79
|
+
# Filter directories in-place to prevent walking into skipped folders
|
|
80
|
+
dirs[:] = [d for d in dirs if not should_skip_path(os.path.join(root, d), exclude_patterns)]
|
|
81
|
+
|
|
82
|
+
for file in files:
|
|
83
|
+
if file.endswith('.py'):
|
|
84
|
+
full_path = os.path.join(root, file)
|
|
85
|
+
if not should_skip_path(full_path, exclude_patterns):
|
|
86
|
+
py_files.append(full_path)
|
|
87
|
+
return py_files
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 2. Processing Strategy & Summary
|
|
91
|
+
```python
|
|
92
|
+
def process_directory(path, dry_run=False, inplace=False, exclude_patterns=None):
|
|
93
|
+
py_files = collect_py_files(path, exclude_patterns)
|
|
94
|
+
|
|
95
|
+
if not py_files:
|
|
96
|
+
print(f"❌ No Python files found in {path}")
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
print(f"📁 Found {len(py_files)} Python files in {path}\n")
|
|
100
|
+
|
|
101
|
+
stats = {"modified": 0, "unchanged": 0, "failed": 0, "total_added": 0}
|
|
102
|
+
|
|
103
|
+
for idx, file_path in enumerate(py_files, 1):
|
|
104
|
+
display_path = Path(file_path).relative_to(path) if path != '.' else Path(file_path).name
|
|
105
|
+
print(f"Processing {idx}/{len(py_files)}: {display_path} ... ", end='')
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
result = generate_docstring(file_path, inplace=inplace, dry_run=dry_run)
|
|
109
|
+
if result.added_count > 0:
|
|
110
|
+
print(f"✅ (+{result.added_count} docstrings)")
|
|
111
|
+
stats["modified"] += 1
|
|
112
|
+
stats["total_added"] += result.added_count
|
|
113
|
+
else:
|
|
114
|
+
print(f"⚠️ (no changes needed)")
|
|
115
|
+
stats["unchanged"] += 1
|
|
116
|
+
except Exception as e:
|
|
117
|
+
print(f"❌ (Error: {str(e)})")
|
|
118
|
+
stats["failed"] += 1
|
|
119
|
+
|
|
120
|
+
# Final Report Output...
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 3. Configuration File Enhancement (`.pycodecommenter.yaml`)
|
|
124
|
+
```yaml
|
|
125
|
+
exclude:
|
|
126
|
+
- "tests/*"
|
|
127
|
+
- "*/migrations/*"
|
|
128
|
+
- "**/__pycache__/*"
|
|
129
|
+
- "*.test.py"
|
|
130
|
+
|
|
131
|
+
use_gitignore: true
|
|
132
|
+
|
|
133
|
+
skip_extensions:
|
|
134
|
+
- ".txt"
|
|
135
|
+
- ".md"
|
|
136
|
+
- ".json"
|
|
137
|
+
- ".yaml"
|
|
138
|
+
|
|
139
|
+
skip_dirs:
|
|
140
|
+
- ".venv"
|
|
141
|
+
- "node_modules"
|
|
142
|
+
- "build"
|
|
143
|
+
- "docs"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Example User Experience
|
|
149
|
+
|
|
150
|
+
### ❌ Before (Current)
|
|
151
|
+
```bash
|
|
152
|
+
$ pycodecommenter generate ./PyCodeCommenter/ --dry-run
|
|
153
|
+
Error reading file: [Errno 21] Is a directory: './PyCodeCommenter/'
|
|
154
|
+
Error: Could not parse ./PyCodeCommenter/
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### ✅ After (Enhanced)
|
|
158
|
+
```bash
|
|
159
|
+
$ pycodecommenter generate ./PyCodeCommenter/ --dry-run
|
|
160
|
+
📁 Found 12 Python files in ./PyCodeCommenter/
|
|
161
|
+
📂 Skipped: .venv/, __pycache__/, .git/, docs/
|
|
162
|
+
📄 Skipped: config.json, *.md, *.yaml
|
|
163
|
+
|
|
164
|
+
Processing 1/12: __init__.py ... ✅ (+2 docstrings)
|
|
165
|
+
Processing 2/12: commenter.py ... ✅ (+3 docstrings)
|
|
166
|
+
...
|
|
167
|
+
Processing 10/12: tests/test_commenter.py ... ⏭️ (skipped - excluded)
|
|
168
|
+
|
|
169
|
+
================================================================
|
|
170
|
+
📊 Summary Report
|
|
171
|
+
================================================================
|
|
172
|
+
✅ Files modified: 7
|
|
173
|
+
⚠️ Files unchanged: 3
|
|
174
|
+
⏭️ Files skipped: 1
|
|
175
|
+
❌ Files failed: 1
|
|
176
|
+
📝 New docstrings: 21
|
|
177
|
+
📁 Total files: 11
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Implementation Roadmap
|
|
183
|
+
|
|
184
|
+
* **Phase 1:** Basic recursive directory support with hardcoded skip patterns.
|
|
185
|
+
* **Phase 2:** Progress reporting, summary statistics, and error handling.
|
|
186
|
+
* **Phase 3:** Integration of `.pycodecommenter.yaml` and `.gitignore` support.
|
|
187
|
+
* **Phase 4:** Performance optimization via parallel processing for large projects.
|
|
188
|
+
* **Phase 5:** Interactive mode (selective file processing).
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Testing Strategy
|
|
193
|
+
| Scenario | Expected Behavior |
|
|
194
|
+
| :--- | :--- |
|
|
195
|
+
| **Empty Directory** | Graceful "No files found" message. |
|
|
196
|
+
| **Deep Nesting** | Traverse 10+ levels without stack overflow. |
|
|
197
|
+
| **Mixed File Types** | Filter out `.js`, `.md`, `.json`, etc. |
|
|
198
|
+
| **Virtual Envs** | Automatically detect and skip `.venv/` or `env/`. |
|
|
199
|
+
| **Invalid Syntax** | Log error for that specific file and continue to the next. |
|
|
200
|
+
| **Permissions** | Skip files with "Permission Denied" and log as failed. |
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Edge Case Handling
|
|
205
|
+
* **Broken Symlinks:** Skip with a warning.
|
|
206
|
+
* **Large Projects:** Use streaming output and efficient memory management.
|
|
207
|
+
* **Cross-Platform:** Normalize paths for Windows and Linux compatibility.
|
|
208
|
+
* **Recursion Limits:** Configurable max depth to prevent infinite loops on circular symlinks.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pycodecommenter
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Automatically generate, validate, and measure Google-style Python docstrings. Deterministic AST-based docstring generator and validator with CI/CD integration, coverage reporting, and JSON output.
|
|
5
5
|
Author-email: "Nabasa Amos(Amos Quety)" <amosnabasa4@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,7 +13,6 @@ Classifier: Development Status :: 4 - Beta
|
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -27,10 +26,11 @@ Classifier: Topic :: Utilities
|
|
|
27
26
|
Classifier: Environment :: Console
|
|
28
27
|
Classifier: Operating System :: OS Independent
|
|
29
28
|
Classifier: Typing :: Typed
|
|
30
|
-
Requires-Python: >=3.
|
|
29
|
+
Requires-Python: >=3.9
|
|
31
30
|
Description-Content-Type: text/markdown
|
|
32
31
|
License-File: LICENSE
|
|
33
32
|
Requires-Dist: ruamel.yaml>=0.17
|
|
33
|
+
Requires-Dist: libcst>=1.1
|
|
34
34
|
Provides-Extra: dev
|
|
35
35
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
36
36
|
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
@@ -48,7 +48,7 @@ Dynamic: license-file
|
|
|
48
48
|
|
|
49
49
|
**PyCodeCommenter** is an open-source Python docstring generator and documentation validator. It automatically generates Google-style docstrings from Python AST, validates existing docstrings against real function signatures, measures documentation coverage, and integrates with CI/CD pipelines — all with zero network calls and zero AI dependency.
|
|
50
50
|
|
|
51
|
-
> **Install:** `pip install pycodecommenter` · **Python 3.
|
|
51
|
+
> **Install:** `pip install pycodecommenter` · **Python 3.9+** · **MIT License**
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
@@ -156,7 +156,7 @@ pycodecommenter validate src/api.py --output-format json
|
|
|
156
156
|
|
|
157
157
|
### Modern Python Support
|
|
158
158
|
|
|
159
|
-
- Python 3.
|
|
159
|
+
- Python 3.9, 3.10, 3.11, 3.12.
|
|
160
160
|
- `async def` functions.
|
|
161
161
|
- Complex type hints: `Union`, `Optional`, `Generic`, `list[int]`, `int | str`.
|
|
162
162
|
- PEP 604 unions, PEP 585 generics.
|
|
@@ -292,7 +292,7 @@ repos:
|
|
|
292
292
|
PyCodeCommenter is a Python command-line tool and library for automatically generating Google-style docstrings and validating existing docstrings against real function signatures.
|
|
293
293
|
|
|
294
294
|
**How do I install PyCodeCommenter?**
|
|
295
|
-
Run `pip install pycodecommenter`. Python 3.
|
|
295
|
+
Run `pip install pycodecommenter`. Python 3.9 or later is required.
|
|
296
296
|
|
|
297
297
|
**Does PyCodeCommenter use AI or LLMs?**
|
|
298
298
|
No. PyCodeCommenter is fully deterministic. It uses Python's built-in `ast` module to parse code and generate documentation. There are no API calls, no network requests, and no rate limits.
|
|
@@ -301,7 +301,7 @@ No. PyCodeCommenter is fully deterministic. It uses Python's built-in `ast` modu
|
|
|
301
301
|
No. Existing summaries, parameter descriptions, and return descriptions are preserved and merged. Only missing sections are filled in automatically.
|
|
302
302
|
|
|
303
303
|
**What docstring styles does PyCodeCommenter support?**
|
|
304
|
-
PyCodeCommenter generates Google-style docstrings. It can parse
|
|
304
|
+
PyCodeCommenter generates Google-style docstrings. It can parse Google-style, Sphinx-style (`:param:`, `:type:`, `:returns:`, `:raises:`), and NumPy-style (`Parameters`/`Returns`/`Raises` with dash-underlined headers) as input.
|
|
305
305
|
|
|
306
306
|
**Can I use PyCodeCommenter in CI/CD?**
|
|
307
307
|
Yes. The `validate` subcommand exits with code `1` when any ERROR-level issue is found, making it suitable for blocking CI builds. The `--output-format json` flag enables integration with any downstream tooling.
|
|
@@ -351,9 +351,9 @@ Full documentation: **[https://amosquety.github.io/PyCodeCommenter/](https://amo
|
|
|
351
351
|
## Supported Platforms & Environments
|
|
352
352
|
|
|
353
353
|
- **OS**: Linux, macOS, Windows
|
|
354
|
-
- **Python**: 3.
|
|
354
|
+
- **Python**: 3.9, 3.10, 3.11, 3.12
|
|
355
355
|
- **Environments**: local, CI/CD (GitHub Actions, GitLab CI, Jenkins), pre-commit hooks
|
|
356
|
-
- **Dependencies**:
|
|
356
|
+
- **Dependencies**: `ruamel.yaml` (config files), `libcst` (docstring patching) — no AI/LLM dependency
|
|
357
357
|
|
|
358
358
|
---
|
|
359
359
|
|
|
@@ -361,7 +361,6 @@ Full documentation: **[https://amosquety.github.io/PyCodeCommenter/](https://amo
|
|
|
361
361
|
|
|
362
362
|
- Python 2.x is not supported (EOL).
|
|
363
363
|
- `match` statements (Python 3.10+) have basic support.
|
|
364
|
-
- NumPy-style docstrings are not parsed as input.
|
|
365
364
|
|
|
366
365
|
---
|
|
367
366
|
|
|
@@ -370,9 +369,9 @@ Full documentation: **[https://amosquety.github.io/PyCodeCommenter/](https://amo
|
|
|
370
369
|
- [ ] VS Code extension
|
|
371
370
|
- [ ] Smart docstring updates that preserve human-written content
|
|
372
371
|
- [ ] Optional AI-powered description generation
|
|
373
|
-
- [
|
|
372
|
+
- [x] NumPy and full Sphinx style support (v2.3.0)
|
|
374
373
|
- [ ] GitHub Action for automated documentation PRs
|
|
375
|
-
- [
|
|
374
|
+
- [x] `--fail-below` flag for coverage threshold enforcement in CLI (v2.3.0)
|
|
376
375
|
|
|
377
376
|
---
|
|
378
377
|
|