Skip to content

Preserve initializer behavior when removing inlined variables - #903

Open
yangfan-yf-yf wants to merge 2 commits into
python-rope:masterfrom
yangfan-yf-yf:fix/inline-initializer-removal
Open

yangfan-yf-yf wants to merge 2 commits into
python-rope:masterfrom
yangfan-yf-yf:fix/inline-initializer-removal

Conversation

@yangfan-yf-yf

@yangfan-yf-yf yangfan-yf-yf commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Inlining a variable with remove=True can erase behavior at its definition, even when there is no executed read of the variable. For example, removing target = missing changes a caught NameError into successful execution of the following statements. A syntactic read under if False does not prevent this change. Deleting an annotated definition can also discard its annotation and the effects observed when annotations are evaluated.

I check these cases before producing changes. I refuse to remove a definition when its initializer name cannot be shown to be bound, when a module or class annotation would be discarded, or when a reference remains outside the selected resources or only_current occurrence. Without reads, I allow supported literal initializers and names whose existing binding is established. Ordinary cases such as value = 42; target = value; print(target) remain supported, including the corresponding unused bound-name deletion.

remove=False keeps the definition while selected reads are inlined. Selecting only a consumer also keeps the provider definition. Function-local name annotations, which are not evaluated, continue to allow removal with a supported initializer. I added execution regressions that check both output and actual source changes, plus atomic refusal cases that leave all files unchanged.

This change is limited to definition removal in InlineVariable. It shares the entry point with #894 and #897, but does not include their annotation-reference or lambda-binding changes and does not require either PR. It does not establish general equivalence for moving arbitrary expressions to their reads.

Validation:

  • The 33 new execution regressions and 102 existing Inline tests pass on Python 3.12 and 3.14. The complete suite passes on Python 3.12 (2182 passed, 12 skipped, 5 xfailed) and Python 3.14 (2186 passed, 8 skipped, 5 xfailed), with 2199 collected on each version.
  • Nine public-API execution controls passed on each version for the product change, including deletion of an outer binding and an unrelated local name deletion. The test-only addition keeps that product code unchanged and adds seven normal behavior controls; four representative independent controls also pass on each version. Black, isort, all five configured hooks, and the diff check pass.

Check initializer names, annotations, and remaining reads before removing
an inlined variable definition. Keep supported literal and bound-name
deletions and preserve definitions when removal is disabled or excluded.

Add execution regressions for refusal and successful inlining cases.
@codecov

codecov Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.20000% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.36%. Comparing base (22f5e50) to head (e6b1763).

Files with missing lines Patch % Lines
rope/refactor/inline.py 92.94% 6 Missing ⚠️
...opetest/refactor/inline_unused_initializer_test.py 99.39% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #903      +/-   ##
==========================================
+ Coverage   95.34%   95.36%   +0.02%     
==========================================
  Files         134      135       +1     
  Lines       26762    27012     +250     
==========================================
+ Hits        25516    25761     +245     
- Misses       1246     1251       +5     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Check builtin, parameter, function, and imported aliases through changed
source and execution, preserve outer bindings across unrelated literals,
and verify atomic refusal for class-scope name initializers.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant