Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
af46618
TypeVar: First initial version with testing
FrancescoPezzella Aug 26, 2026
4545243
TypeVar: Expanded upon the TypeVars - TypeVar/ParamSpec/TypeVarTuple.…
FrancescoPezzella Aug 26, 2026
cd98ca5
TypeVar: Added type checking and fixed as many linter problems that c…
FrancescoPezzella Aug 26, 2026
6697423
Fixed a TODO bug with Snake_Case, file names with 2+ words were not c…
FrancescoPezzella Aug 27, 2026
b798fa5
Extended TypeVarCheck to fully modernize TypeVar/ParamSpec/TypeVarTup…
FrancescoPezzella Aug 28, 2026
f20af58
Fixed ASTNode.node being untyped (pyright inferred it as always None,…
FrancescoPezzella Aug 28, 2026
d84741a
Fixed docs to pass the docs-quality CI (pymarkdown scan): wrapped par…
FrancescoPezzella Aug 28, 2026
2094aa4
Added a Python-version gate to TypeVarCheck (PEP 695 conversion only …
FrancescoPezzella Aug 28, 2026
b52bf37
Fixed PythonRstNode crashing and silently dropping part of the AST wh…
FrancescoPezzella Aug 31, 2026
ff36f77
Extracted type_var_domain.py (TypeVar/ParamSpec/TypeVarTuple domain m…
FrancescoPezzella Aug 31, 2026
5cc1b71
Fixed the 6 pyright strict findings in type_var_check.py/type_var_dom…
FrancescoPezzella Aug 31, 2026
d96fd32
Fix silent corruption when two rewrites target the same node (ast_rew…
FrancescoPezzella Aug 31, 2026
490ac54
Fix silent corruption when two rewrites target the same node (ast_rew…
FrancescoPezzella Aug 31, 2026
5e2153d
Fix TypeVarCheck corrupting or losing code during PEP 695 conversion
FrancescoPezzella Sep 1, 2026
1194d10
Ruff: Fixed and enabled (W)hitespace rule
FrancescoPezzella Sep 1, 2026
a09b620
Ruff: Enabled all unsafe fixes from other rules
FrancescoPezzella Sep 1, 2026
2c08d93
Fixed ruff releated formatting issues
FrancescoPezzella Sep 1, 2026
5c41342
Fix 2
FrancescoPezzella Sep 2, 2026
1750d37
Applied ruff fixes
FrancescoPezzella Sep 2, 2026
ce7022d
Ruff fixes
FrancescoPezzella Sep 7, 2026
229e7fb
Add migration-type-recipes.py CLI for TypeVarCheck
FrancescoPezzella Sep 8, 2026
802f5ce
CLI - both typevar and typevartuplecheck integrated
FrancescoPezzella Sep 8, 2026
af0ea7b
CLI documentation
FrancescoPezzella Sep 8, 2026
520737c
Add Step/run_steps, refactor TypeVarCheck.check() to use it
FrancescoPezzella Sep 9, 2026
248c1e3
Removed dead code (which became irrelevant some ago), cleaned up some…
FrancescoPezzella Sep 9, 2026
a9c749b
Delegate unused-import cleanup to ruff F401 (CLI will call Ruff, no n…
FrancescoPezzella Sep 9, 2026
7a543da
Rewrite CLI: remove dry-run (issues, easier to remove, git diff alrea…
FrancescoPezzella Sep 9, 2026
0179b64
Updated and cleaned up notes
FrancescoPezzella Sep 9, 2026
121dee5
Small fixes for something that would will be removed soon anyways
FrancescoPezzella Sep 9, 2026
538d4c7
Marked two tests as failing due to an earlier fix
FrancescoPezzella Sep 10, 2026
1fc5874
Quote TYPE_CHECKING-only annotation, scope UP037 noqa to one line
FrancescoPezzella Sep 10, 2026
af842c8
Ruff unsafe fix
FrancescoPezzella Sep 11, 2026
4b4d3d1
Updated outdated documentation
FrancescoPezzella Sep 11, 2026
d103764
'--review' now gives more information to the user regarding Type reci…
FrancescoPezzella Sep 11, 2026
1880bf0
Removed code duplication, fixed incorrect paths to files (before refa…
FrancescoPezzella Sep 11, 2026
2179cb0
Fixed a bug with the correct Python version not being identified by t…
FrancescoPezzella Sep 11, 2026
d78c3f8
Fix broken test
FrancescoPezzella Sep 11, 2026
1602136
Updated outdated Docs - removed references to deleted Python Kind Map
FrancescoPezzella Sep 14, 2026
0b5dd44
New bug documented
FrancescoPezzella Sep 14, 2026
db005c4
Added feedback when processing each file with the Migration tool.
FrancescoPezzella Sep 14, 2026
22ecddd
Updated python-ast doc
FrancescoPezzella Sep 14, 2026
82c1c08
Updated doc
FrancescoPezzella Sep 14, 2026
baf6d36
Updated doc 2x
FrancescoPezzella Sep 14, 2026
e8321c6
docs- removed everything that has been handled by other PRs, issues o…
FrancescoPezzella Sep 15, 2026
70ae6af
Fix
FrancescoPezzella Sep 15, 2026
d63c90d
Forced UTF until becomes Py 3.15 default
FrancescoPezzella Sep 16, 2026
eb8e9d0
New test, and cleaned up some old comments for tests
FrancescoPezzella Sep 17, 2026
620b8cd
typevar modernization - doc on HOW to fix unsafe-fixes manually
FrancescoPezzella Sep 18, 2026
82f01ee
Deleted incorrect files added during the rebase
FrancescoPezzella Sep 21, 2026
3853215
Rebase mistakes-
FrancescoPezzella Sep 21, 2026
7cbedc9
Last rebase mistake
FrancescoPezzella Sep 21, 2026
76e25d2
Add missing docstrings, reword existing ones, add missing import
FrancescoPezzella Sep 21, 2026
f20ba89
TypeVar issues
FrancescoPezzella Sep 21, 2026
e7b9f68
Add project-wide import safety to TypeVar localization
FrancescoPezzella Sep 22, 2026
8efbc05
Add missing docstrings to TypingRecipe related tests
FrancescoPezzella Sep 23, 2026
dd4c54b
New test that shows a fault in the CLI
FrancescoPezzella Sep 23, 2026
aa4b503
Fix project_root wiring and relative paths in TypeVar import safety
FrancescoPezzella Sep 23, 2026
8f83ed5
Clean up comments and doc strings
FrancescoPezzella Sep 23, 2026
436f72a
Doc update
FrancescoPezzella Sep 23, 2026
5f057c5
Add TODOs to migration tool
FrancescoPezzella Sep 23, 2026
59d4172
Access TypeVars as model attributes
FrancescoPezzella Sep 23, 2026
b6c0f79
Adjust CLI message and resolve path
FrancescoPezzella Sep 23, 2026
23e7905
Fix outdated references
FrancescoPezzella Sep 23, 2026
ebf4cc8
Cleaner docstring
FrancescoPezzella Sep 24, 2026
1e985a4
Add TODO to a workaround that should be replaced by NodeProtocol, onc…
FrancescoPezzella Sep 24, 2026
2d9569b
Tool no longer looks for a Python Version in the project: was suspect…
FrancescoPezzella Sep 24, 2026
8448df6
Update outdated typevar/recipe doc
FrancescoPezzella Sep 24, 2026
3d2e659
Removed failing test: CI/CD uses Linux environment (which is UTF-8 by…
FrancescoPezzella Sep 24, 2026
6e64fdb
Added an optional cmd for the user to not run Ruff with --no-ruff. Th…
FrancescoPezzella Sep 25, 2026
b7b3466
Fix issue with narrowed_import_text() dropping ".." from relative imp…
FrancescoPezzella Sep 29, 2026
55c917d
Refuse to localize a TypeVar whose origin imports its constructor con…
FrancescoPezzella Sep 30, 2026
b71f3d1
Delete outdated document and its references, which has been replaced
FrancescoPezzella Oct 2, 2026
116dd99
Revert changes in ast_refactor_actions (handled in a separate PR)
FrancescoPezzella Oct 2, 2026
6120c5c
Fix stale docs for the TypeVar recipes and document known limitations
FrancescoPezzella Oct 2, 2026
ff2e172
Pymarkdown fix
FrancescoPezzella Oct 2, 2026
7ca9eeb
TODOs for 2 bugs
FrancescoPezzella Oct 2, 2026
ba61f83
Remove disabled Ruff rule ignores, Clean up docstring and comment
FrancescoPezzella Oct 2, 2026
e572ded
Bug fix with Project Scanner: no longer enters excluded carpets, savi…
FrancescoPezzella Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions docs/TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

## Documentation gaps: action points for docs

### Stub pages that need content
Expand Down Expand Up @@ -35,9 +34,8 @@

15. **Scoping: skip and filter at the file level** (add to strategy-composition.md or a new page) — Java's `skipATU`, `globalFilter`, `sourceFilePostfixes`, and `sourceFileDirectories` provide coarse-grained scoping before any pattern matching runs. The Python equivalent concept needs documentation.


### New pages worth adding

19. **Common parser problems** (new page, e.g., `docs/developer/modules/parser-known-limitations.md`) — Java has CommonCdtParsingProblems.md listing concrete CDT/MSVC-extension parsing failures with workarounds. A Python equivalent covering known tree-sitter, libcst, clang binding, and ANTLR limitations would be directly useful.
19. **Common parser problems** (new page, e.g., `docs/developer/modules/common-parser-problems.md`) — Java has CommonCdtParsingProblems.md listing concrete CDT/MSVC-extension parsing failures with workarounds. A Python equivalent covering known tree-sitter, libcst, clang binding, and ANTLR limitations would be directly useful (the Python `ast` limitations are already covered by `python-ast-known-limitations.md`).

20. **Related works and context** (new section in index.md or index.md) — The Java UserGuide.md relates the tool to WHARS and ADA tooling. Adding a "related works" section that situates Renaissance-Experiments relative to the Java version, comby, and other code transformation tools would help new contributors understand design choices.
20. **Related works and context** (new section in index.md or index.md) — The Java UserGuide.md relates the tool to WHARS and ADA tooling. Adding a "related works" section that situates Renaissance-Experiments relative to the Java version, comby, and other code transformation tools would help new contributors understand design choices.
43 changes: 41 additions & 2 deletions docs/developer/feature-test-map/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,52 @@
## 1. Pattern matching

- **Feature:** [Pattern matching](../../user/features/pattern-matching.md)
- **Suggested test modules:** `tests/matching/`
- **Test file(s):**
- `test/syntax_tree/test_match_finder.py`
- `test/syntax_tree/test_match_finder_multi_assignments.py`
- `test/syntax_tree/test_match_tree.py`
- `test/syntax_tree/test_match_dict.py`
- `test/syntax_tree/test_pattern_match.py`
- `test/syntax_tree/test_pattern_kind.py`
- `test/python/ast/test_python_matcher.py`
- `test/c_cpp/test_c_match_finder.py`
- **Code file(s):** `src/renaissance/syntax_tree/match_finder.py`, `src/renaissance/syntax_tree/pattern_kind.py`

## 2. Rewrite semantics

- **Feature:** [Rewrite semantics](../../user/features/rewrite-semantics.md)
- **Concepts:** [Rewrite semantics](../../user/concepts/rewrite-semantics.md)
- **Test modules:** [Rewrite semantics test module](../../developer/modules/rewrite-semantics.md)
- **BDD feature file:** `features/rewrite-semantics.feature`
- **BDD steps:** `features/steps/test-rewrite-semantics.py`
- **BDD steps:** `features/steps/test_rewrite_semantics.py`
- **Test file(s):**
- `test/common/test_rewriter.py`
- `test/syntax_tree/test_ast_rewriter.py`
- `test/syntax_tree/test_rewrite_semantics_properties.py`
- **Code files:** `src/renaissance/common/rewriter.py`, `src/renaissance/syntax_tree/ast_rewriter.py`

## 3. TypeVar modernization

- **Feature:** [TypeVar modernization](../../user/features/typevar-modernization.md)
- **Concepts:** [Python version gates](../../user/concepts/python-version-gates.md)
- **Code modules:** [Refactoring recipes](../../developer/modules/recipes.md)
- **Test file(s):**
- `test/recipes/test_type_var_check.py`
- `test/recipes/test_type_var_check_convert.py`
- `test/recipes/test_type_var_check_localize.py`
- `test/recipes/test_type_var_check_orphaned.py`
- `test/recipes/test_type_var_check_properties.py`
- `test/recipes/test_type_var_tuple_check.py`
- `test/recipes/test_type_var_tuple_check_fix.py`
- `test/recipes/test_type_var_tuple_check_properties.py`
- `test/recipes/test_type_var_domain.py`
- `test/recipes/test_step_runner.py`
- `test/recipes/test_python_refactoring.py`
- `test/recipes/conftest.py`
- `test/utils/test_unparse_utils.py`
- `test/utils/test_import_resolution.py`
- `test/rejuvenation/test_migration_type_recipes.py`
- **Code file(s):** `src/renaissance/recipes/type_var_check.py`, `src/renaissance/recipes/type_var_tuple_check.py`,
`src/renaissance/recipes/type_var_domain.py`, `src/renaissance/recipes/step_runner.py`,
`src/renaissance/recipes/python_refactoring.py`, `src/renaissance/utils/unparse_utils.py`,
`src/renaissance/utils/import_resolution.py`, `src/rejuvenation/migration-type-recipes.py`
3 changes: 3 additions & 0 deletions docs/developer/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
5. [Transformation modules](transformation.md)
6. [Observability modules](observability.md)
7. [Strategy modules](strategy.md)
8. [Rewrite semantics module](rewrite-semantics.md)
9. [Refactoring recipes](recipes.md)
10. [Python AST known limitations](python-ast-known-limitations.md)
70 changes: 70 additions & 0 deletions docs/developer/modules/python-ast-known-limitations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Python AST known limitations

{ #codemod-python-ast-known-limitations }

**Stable ID:** `CODEMOD-PYTHON_AST_KNOWN_LIMITATIONS`

Concrete limitations found in the Python AST/RST layer (`renaissance.integrations.python.ast`) and the rewrite mechanism it
feeds (`renaissance.syntax_tree.ast_rewriter`, `renaissance.utils.text_utils`) while building recipes
(`TypeVarCheck`, `TypeVarTupleCheck`). A recipe still has to work around both items below. Item 1 has no other
tracker in the codebase. Item 2 is also tracked by a `# TODO` at the `return` in `ast_rewriter.py`, by `xfail`
scenarios in `features/steps/test_rewrite_semantics.py` and `test/syntax_tree/test_ast_rewriter.py`, and by tests
skipped with `TODO: fix impl.` in the latter; this page records why the obvious fix does not work.

## 1. `ast.unparse()`/`shift_right` lose comments and indentation

`TextUtils.shift_right`/`shift_left` (`renaissance/utils/text_utils.py`) are pure text operations with no notion of
Python syntax - they shift every line in a range unconditionally, blind to whether a line sits inside a string
literal. `ast.unparse()` already reproduces a docstring's continuation lines verbatim (it's the only multi-line
string constant it emits as a real multi-line literal), so a whole-function/class/module replacement built from
it shifts those already-correctly-indented lines a second time. Separately, regenerating a function's entire body
from the AST also reformats it to `ast.unparse()`'s own style regardless of the original formatting, and -
permanently, since Python's `ast` module never records comments at all - **deletes every comment inside the
body**; there is nothing for `ast.unparse()` to reproduce, and no future fix to this framework can change that
without Python itself changing. Both are real for any recipe that regenerates a whole node's source via
`ast.unparse()` and replaces the original text with it wholesale.

**`TypeVarCheck` avoids this, it doesn't fix it** - see [Refactoring recipes](../../developer/modules/recipes.md)
for how `unparse_signature_only` splices only the new `[T]`/`[**P]`/`[*Ts]` bracket into the function's original
text instead of regenerating anything via `ast.unparse()`.

The avoidance is not complete. `unparse_signature_only` still re-indents the function's lines (`_renormalize_indent`),
taking the *smallest* indentation among the body's non-blank lines as the body's own indentation, and that is
blind to string literals too. A multi-line string literal in the body with a continuation line indented less than
the body (for example at column 0) lowers that minimum: the function is re-indented from the wrong baseline and
the literal's contents change silently (`'first\nsecond'` becomes `'first\n second'`). This reproduces with
`TypeVarCheck.convert_declared_typevars` on both a module-level function and a method; a literal whose
continuation lines are indented like the body is not affected.

A future recipe that genuinely needs to regenerate a whole body from the AST - not just a signature - still hits
both issues above and has to work around them itself; neither `ast.unparse()`'s comment blindness nor
`shift_right`/`shift_left`'s string-literal blindness was touched here.

## 2. `__is_ancestor_in_nodes` can't just drop its `and False`

`_RewriteActions.__is_ancestor_in_nodes` (`renaissance/syntax_tree/ast_rewriter.py`) is meant to detect when a
queued rewrite is nested inside another queued rewrite's node, so `apply()` can skip the redundant nested one and
let the outer (ancestor) rewrite silently dominate it - but it ends with `return result and False`, which is
always `False` regardless of `result`. The dominance/suppression check never fires: an ancestor replacement and a
nested descendant edit queued in the same batch both get applied instead of the descendant being suppressed. The
one-line in-code `# TODO` at that `return` doesn't capture why this isn't a one-line fix, so it's spelled out here
instead.

**Why the obvious one-line fix doesn't work:** simply changing `return result and False` to `return result`
does not enable the suppression correctly. `no_conflict(node, rew)` returns `True` for `node is rew` (a node
trivially "overlaps" itself), and `rewrite_nodes` is built by flattening every rewrite in `self.rewrites` - the
same collection `apply()` draws `n` from when it calls `__is_ancestor_in_nodes(n)`. So `result` is a near-total
tautology: `True` for almost any node, since it always includes a self-comparison. Dropping `and False` would
make `__is_ancestor_in_nodes` return `True` for nearly every queued node - including nodes that have no real
ancestor/descendant relationship to anything else - so `apply()`'s `continue` would skip most rewrites, not
just the dominated ones, breaking the majority of currently-passing scenarios rather than fixing the dominance
scenarios that are marked `xfail` (for example `test_dominated_change_not_applied` in
`features/steps/test_rewrite_semantics.py`). A real fix needs to exclude a node's own rewrite from the comparison set and use a genuine
ancestor/descendant check - e.g. reusing `__is_nested` (already used by `__check_for_conflicting_rewrites`, the
sibling check that turns a *different* kind of overlapping-rewrite bug into a clear `ValueError` instead of
corrupting output) - instead of repairing `no_conflict`'s offset-overlap test.

`TypeVarCheck` avoids triggering this gap by construction: `functions_using_nodes` attributes a name to the
outermost function using it, so a nested closure never gets an edit of its own alongside its parent's. See
[Refactoring recipes](recipes.md), which also describes how `convert_declared_typevars` queues exactly one edit per
function, never a second rewrite on the same node.
Loading
Loading