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.
Files changed (76) hide show
  1. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.well-known/ai-plugin.json +1 -1
  2. pycodecommenter-2.3.0/CHANGELOG.md +167 -0
  3. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/CITATION.cff +2 -2
  4. pycodecommenter-2.3.0/Future Work/More future work prompt.md +82 -0
  5. pycodecommenter-2.3.0/Future Work/More future work.md +208 -0
  6. {pycodecommenter-2.2.0/pycodecommenter.egg-info → pycodecommenter-2.3.0}/PKG-INFO +11 -12
  7. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/__init__.py +1 -1
  8. pycodecommenter-2.3.0/PyCodeCommenter/cli.py +297 -0
  9. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/commenter.py +119 -50
  10. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/coverage.py +35 -3
  11. pycodecommenter-2.3.0/PyCodeCommenter/docstring_parser.py +215 -0
  12. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/inference.py +20 -4
  13. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/validator.py +15 -6
  14. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/README.md +8 -9
  15. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/index.md +4 -4
  16. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/llms.txt +3 -3
  17. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0/pycodecommenter.egg-info}/PKG-INFO +11 -12
  18. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/SOURCES.txt +3 -0
  19. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/requires.txt +1 -0
  20. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pyproject.toml +3 -4
  21. pycodecommenter-2.3.0/test_docstring_parser.py +120 -0
  22. pycodecommenter-2.3.0/test_edge_cases.py +334 -0
  23. pycodecommenter-2.2.0/CHANGELOG.md +0 -63
  24. pycodecommenter-2.2.0/PyCodeCommenter/cli.py +0 -130
  25. pycodecommenter-2.2.0/PyCodeCommenter/docstring_parser.py +0 -121
  26. pycodecommenter-2.2.0/test_edge_cases.py +0 -58
  27. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.github/workflows/docs.yml +0 -0
  28. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.github/workflows/publish.yml +0 -0
  29. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/.gitignore +0 -0
  30. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/CONTRIBUTING.md +0 -0
  31. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/Future Release WorkPlan.txt +0 -0
  32. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/Vulnerabilties.md +0 -0
  33. {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
  34. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/v2.2.0 /342/200/224 Accuracy & Output.txt" +0 -0
  35. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/v3.0.0 /342/200/224 Safe, Configurable, Extensible.txt" +0 -0
  36. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/Future Work/v3.1.0 /342/200/224 Integrations.txt" +0 -0
  37. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/LICENSE +0 -0
  38. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/config.py +0 -0
  39. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/parameter_descriptions.py +0 -0
  40. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/templates.py +0 -0
  41. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/PyCodeCommenter/type_analyzer.py +0 -0
  42. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/conftest.py +0 -0
  43. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/assets/.gitkeep +0 -0
  44. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/changelog.md +0 -0
  45. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/cli-reference.md +0 -0
  46. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/configuration.md +0 -0
  47. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/contributing.md +0 -0
  48. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/docstring-styles.md +0 -0
  49. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/faq.md +0 -0
  50. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/getting-started.md +0 -0
  51. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/javascripts/custom.js +0 -0
  52. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/python-api.md +0 -0
  53. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/recipes.md +0 -0
  54. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/robots.txt +0 -0
  55. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/stylesheets/extra.css +0 -0
  56. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/docs/validation-checks.md +0 -0
  57. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/basic_usage.py +0 -0
  58. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/ci_integration.py +0 -0
  59. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/coverage_example.py +0 -0
  60. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/examples/validation_example.py +0 -0
  61. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/main.py +0 -0
  62. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/mkdocs.yml +0 -0
  63. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/dependency_links.txt +0 -0
  64. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/entry_points.txt +0 -0
  65. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/pycodecommenter.egg-info/top_level.txt +0 -0
  66. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/scratch/test_infer.py +0 -0
  67. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/scratch/test_mixed_returns.py +0 -0
  68. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/scratch/test_unicode.py +0 -0
  69. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/setup.cfg +0 -0
  70. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_backwards_compatibility.py +0 -0
  71. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_basic_validation.py +0 -0
  72. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_coverage.py +0 -0
  73. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_integration.py +0 -0
  74. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_modern.py +0 -0
  75. {pycodecommenter-2.2.0 → pycodecommenter-2.3.0}/test_type_analyzer.py +0 -0
  76. {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.2.0",
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.2.0
18
- date-released: "2026-07-12"
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.2.0
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.8
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.8+** · **MIT License**
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.8, 3.9, 3.10, 3.11, 3.12.
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.8 or later is required.
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 both Google-style and Sphinx-style (`:param:`, `:returns:`, `:raises:`) as input.
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.8, 3.9, 3.10, 3.11, 3.12
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**: stdlib only (no third-party runtime dependencies beyond `ruamel.yaml` for config)
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
- - [ ] NumPy and full Sphinx style support
372
+ - [x] NumPy and full Sphinx style support (v2.3.0)
374
373
  - [ ] GitHub Action for automated documentation PRs
375
- - [ ] `--fail-below` flag for coverage threshold enforcement in CLI
374
+ - [x] `--fail-below` flag for coverage threshold enforcement in CLI (v2.3.0)
376
375
 
377
376
  ---
378
377
 
@@ -11,7 +11,7 @@ from .coverage import CoverageAnalyzer, FileCoverage, ProjectCoverage
11
11
  from .type_analyzer import TypeAnalyzer
12
12
  from .docstring_parser import DocstringParser
13
13
 
14
- __version__ = "v2.2.0"
14
+ __version__ = "v2.3.0"
15
15
 
16
16
 
17
17
  __all__ = [