Skip to content

Preserve source encodings when applying refactorings - #2123

Closed
Alex0AI wants to merge 1 commit into
davidhalter:masterfrom
Alex0AI:fix/refactoring-source-encoding
Closed

Alex0AI wants to merge 1 commit into
davidhalter:masterfrom
Alex0AI:fix/refactoring-source-encoding

Conversation

@Alex0AI

@Alex0AI Alex0AI commented Oct 19, 2026

Copy link
Copy Markdown

Summary

Preserve Python source encodings when ChangedFile.apply() writes a refactoring result, and encode the complete result before opening the destination so an encoding error cannot truncate the original file.

Currently, open(path, 'w', newline='') uses the platform default encoding. For example, renaming a variable in a Latin-1 file containing café writes different bytes under a UTF-8 locale, while retaining the Latin-1 coding declaration. Under a Windows GBK locale, even a UTF-8 source file can be silently rewritten as GBK. Characters that cannot be encoded can also raise after the destination has already been truncated.

The change derives the encoding from the refactored source's PEP 263 declaration / UTF-8 BOM using tokenize.detect_encoding. It defaults to UTF-8 for ordinary Python source, retains a single BOM, pre-encodes the text, and writes the bytes without newline conversion. It uses the current source buffer, so refactorings can still create a file whose path does not exist yet.

Tests

Ten new regression cases exercise:

  • UTF-8, UTF-8 with BOM, Latin-1 and Windows-1252 source files;
  • both LF and CRLF line endings, verified byte for byte;
  • an unencodable renamed identifier leaving the original bytes untouched;
  • creation of a new UTF-8 file from an in-memory Script.

On the original code, all ten cases fail on Windows / CPython 3.13.5 with a GBK locale. After the fix:

  • python -m pytest test/test_api/test_refactoring.py test/test_integration.py -k refactor -q --tb=short: 116 passed, 2263 deselected.
  • Pinned Flake8 7.1.2 passed for both modified Python files.
  • git diff --check passed.

The typeshed and django-stubs submodules were initialized at their pinned revisions. The entire completion/inference suite and other interpreter/platform combinations were not run.

Added a changelog entry and Alex0AI to AUTHORS.txt as requested by CONTRIBUTING.md.

This investigation, implementation, tests and PR description were prepared with OpenAI Codex assistance.

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.

2 participants