Repository navigation
Do not interpolate single-quoted values (fixes #422) - #745
36taransingh5-dotcom wants to merge 4 commits into
Conversation
swastiktawate
left a comment
There was a problem hiding this comment.
Correct fix, single-quoted values in a shell are literal, so leaving ${b} alone is the right behaviour. The quote field threading through the parser is neat. One thing to check: resolve_variables now takes 3-item tuples instead of 2. Is that function used anywhere outside the parser where the change could break a direct caller? If it is internal only, this is fine.
|
Thanks for the review. On the question: resolve_variables is only called from DotEnv.dict() in this repo, and it is not documented or re-exported from the package. It is a public name in dotenv.main though, so I can't rule out outside callers that pass 2-item tuples. If you would like, I can make it accept both 2-item and 3-item tuples so such callers keep working. Note that parser.parse_value also now returns a (value, quote) pair, so direct callers of that would see a change too. Happy to adjust either way. |
Problem
set_keywrites values in single quotes intending to preserve them literally, but reading them back withdotenv_values/load_dotenv(which interpolate by default) still expands variable references inside single-quoted values. The value is silently corrupted:This is the round-trip data loss reported in #422.
Root cause
parser.Bindingdiscarded the quote character beforemain.resolve_variablesran, so the resolver had no way to know a value was single-quoted.Fix
parser.parse_valuenow returns the quote character alongside the value, andBindingcarries it in a newquotefield.main.dict()uses a private_parse_full()that keeps the quote triples (the publicparse()shape is unchanged).resolve_variablesreturns single-quoted values verbatim, matching POSIX shell semantics where single quotes inhibit expansion. The literal text of a single-quoted value remains visible to later values, consistent with the existing chained-resolution behaviour: withB='${A}'thenC=${B},Cresolves to the literal text${A}.Interpolation of double-quoted and unquoted values is unchanged.
Test changes
set_keyround-trip and literal single-quote handling.({"b": "c"}, "a='${b}'", True, ...)previously expected{"a": "c"}and now expects the literal{"a": "${b}"}. This is an intentional behaviour change implementing Unable to escape posix expansion #422; flagging it explicitly for review.Fixes #422.
Developed with AI assistance.