fix: make values containing backslashes round-trip through set_key - #680
Open
dchaudhari7177 wants to merge 1 commit into
Open
fix: make values containing backslashes round-trip through set_key#680dchaudhari7177 wants to merge 1 commit into
dchaudhari7177 wants to merge 1 commit into
Conversation
`set_key` writes single-quoted values but only escaped single quotes,
not backslashes. The single-quoted-value parser decodes `\` and `\'`,
so any value with a backslash came back wrong:
set_key(".env", "P", r"C:\Users") # writes P='C:\Users'
get_key(".env", "P") # -> "C:Users"
Escape backslashes before single quotes when writing.
That alone is not enough for a value that ends in a backslash. The
quoted-value patterns treated `\'` as an escape but not `\`, so in
`P='back\'` the second backslash paired with the closing quote. `[^']`
matches newlines, so the match ran on into the following lines and the
binding failed to parse, taking the next entries with it. Both the
single- and double-quoted patterns now treat a backslash as escaping
whatever follows it.
Fixes theskumar#661
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #661.
Problem
set_keywrites single-quoted values and escapes single quotes, but not backslashes. The single-quoted-value parser decodes\and\', so a value containing a backslash does not survive a write/read round-trip:Windows paths and regular expressions are the common victims.
Fix, part 1 — escape on write
value_to_set.replace("\\", "\\\\").replace("'", "\'"). Backslashes first, so the backslash introduced by the quote escaping is not escaped again.Fix, part 2 — the write side alone is not enough
With only part 1, a value ending in a backslash is still broken, and breaks its neighbours too:
_single_quoted_valuewas'((?:\'|[^'])*)'— it knows\'is an escape but not\. So inback\'the second backslash pairs with the closing quote as\', the match keeps going, and since[^']also matches newlines it runs into the next line. The binding then fails_end_of_line, error recovery kicks in, andBis lost as well.Both quoted-value patterns now say "a backslash escapes the next character":
re.DOTALLkeeps multi-line quoted values working, which the old[^']allowed.This is not a behaviour change for anything that parsed correctly before — the captured group is identical for every input the old pattern handled, and
decode_escapesis untouched. It only changes inputs that previously failed to parse. Hand-writtenA='C:\Users\name'still yieldsC:\Users\name, andA='b\'c'still yieldsb'c.Tests
test_set_keygains three cases pinning the written form forb\c,b\andb\'c.test_set_key_round_tripsparametrizes ten values (Windows paths with and without a trailing separator, regexes, quotes, empty) and asserts both that the value comes back intact and that a following key is still readable — that second assertion is what catches the line-swallowing.test_parse_streamgains five cases for escaped backslashes in both quote styles, including the two-binding case.pytest tests/passes. The twotest_cli.py::test_run_*failures on my machine are pre-existing and Windows-specific (they reproduce on an unmodified checkout).🤖 Generated with Claude Code