fix(rename): read and write source files as UTF-8#6761
Conversation
reflex rename reads every .py/.md file in the user's app with Path.read_text() and writes it back with Path.write_text(), neither of which passed encoding=. Both default to the platform locale encoding, which on Western Windows is cp1252 rather than UTF-8. UTF-8-authored source containing non-ASCII bytes (curly quotes, emoji, accented identifiers or docstrings) is therefore silently corrupted on a Western Windows locale, or aborts the rename partway with UnicodeDecodeError on a CJK codepage, leaving the tree in an inconsistent state. Pass encoding="utf-8" on both calls, matching path_ops.find_replace which already does this. Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
Greptile SummaryThis PR makes the rename workflow use UTF-8 explicitly. The main changes are:
Confidence Score: 4/5The rename path can abort and leave files partially updated when an app contains valid non-UTF-8 Python source.
reflex/utils/rename.py Important Files Changed
Reviews (1): Last reviewed commit: "fix(rename): read and write source files..." | Re-trigger Greptile |
| """ | ||
| file_path = Path(file_path) | ||
| content = file_path.read_text() | ||
| content = file_path.read_text(encoding="utf-8") |
There was a problem hiding this comment.
When the app contains valid Python source declared as cp1252 or latin-1, a non-ASCII byte such as 0xe9 now raises UnicodeDecodeError. The rename traversal passes every .py file here and may already have rewritten earlier files, leaving the app partially renamed; detect the source encoding and preserve it instead of always decoding as UTF-8.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 657b04cfd5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| """ | ||
| file_path = Path(file_path) | ||
| content = file_path.read_text() | ||
| content = file_path.read_text(encoding="utf-8") |
There was a problem hiding this comment.
Honor declared Python source encodings
For .py files that are valid Python but declare a non-UTF-8 source encoding (for example # -*- coding: cp1252 -*-) and contain bytes outside UTF-8, this unconditional UTF-8 read now raises UnicodeDecodeError before renaming imports. process_directory applies this to every Python file, so one such module can abort reflex rename part-way through an app; using Python's source-encoding detection for .py files would preserve the fix for UTF-8 files without rejecting valid encoded modules.
Useful? React with 👍 / 👎.
All Submissions:
Type of change
What and why
reflex rename <new_name>walks the user's app and rewrites imports and the appname in every
.pyand.mdfile. The read/modify/write inrename_imports_and_app_name(reflex/utils/rename.py) usedPath.read_text()andPath.write_text()with noencoding=argument, so bothdefault to the platform's locale encoding. On a Western Windows locale that is
cp1252, not UTF-8.The consequences on non-UTF-8 locales:
contains non-ASCII bytes (curly quotes in docstrings, accented identifiers or
string literals, emoji) is decoded as cp1252, rewritten, and written back as
cp1252, mangling the user's own source.
read_text()raisesUnicodeDecodeError,aborting the rename partway through the tree and leaving some files already
rewritten and others not, i.e. an inconsistent app.
On a POSIX UTF-8 locale it round-trips, so this is effectively Windows-specific.
The fix passes
encoding="utf-8"on both calls. This mirrors the repo's ownreflex/utils/path_ops.pyfind_replace, which already reads and writes the sameread/replace/write pattern with
encoding="utf-8";rename.pywas the outlier.Changes
reflex/utils/rename.py: addencoding="utf-8"to theread_text()andwrite_text()calls inrename_imports_and_app_name(+2 / -2).tests/units/test_prerequisites.py: add regression testtest_rename_imports_and_app_name_preserves_utf8, colocated with the existingrename tests. It simulates a cp1252 default (monkeypatching
Path.read_text/write_textso a missingencodingfalls back to cp1252, while an explicitencoding=still passes through), writes a UTF-8 file with realistic non-ASCIIcontent, runs the rename, and asserts the bytes are preserved exactly and the
rename still happened. The test fails before the fix (
UnicodeDecodeError) andpasses after.
news/<pr>.bugfix.md: towncrier changelog fragment.Changes To Core Features:
Locally (all green):
uv run pytest tests/units/test_prerequisites.py -k rename-> 6 passeduv run pytest tests/units/test_prerequisites.py tests/units/utils-> 677 passed, 4 skippeduv run ruff check .(changed files) -> All checks passeduv run ruff format --check .(changed files) -> already formatteduv run pyright reflex/utils/rename.py tests/units/test_prerequisites.py-> 0 errorsuv run towncrier check --compare-with origin/main-> fragment found