Skip to content

Commit f5485a6

Browse files
Bolt4243theskumar
authored andcommitted
fix: parse empty unquoted value with inline comment as empty string
An unquoted empty value followed by an inline comment (e.g. `KEY= # comment`) was parsed as the comment text because the equal-sign regex consumed the whitespace after `=`, leaving no whitespace for the comment-stripping rule to match. When the value is empty (whitespace follows `=`) and starts with `#`, treat the rest of the line as a comment and the value as empty. Values with no space before `#` (e.g. `KEY=#novalue`, `KEY=a#b`) are unchanged. Closes #600
1 parent 49515af commit f5485a6

3 files changed

Lines changed: 100 additions & 2 deletions

File tree

‎src/dotenv/parser.py‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,15 @@ def parse_binding(reader: Reader) -> Binding:
156156
key = parse_key(reader)
157157
reader.read_regex(_whitespace)
158158
if reader.peek(1) == "=":
159-
reader.read_regex(_equal_sign)
160-
value: Optional[str] = parse_value(reader)
159+
(equal_sign,) = reader.read_regex(_equal_sign)
160+
# If there is whitespace after `=` and the value starts with `#`,
161+
# the value is empty and the rest of the line is an inline comment
162+
# (e.g. `KEY= # comment`). Without whitespace (`KEY=#novalue`) the
163+
# `#` is part of the unquoted value.
164+
if len(equal_sign) > 1 and reader.peek(1) == "#":
165+
value: Optional[str] = ""
166+
else:
167+
value = parse_value(reader)
161168
else:
162169
value = None
163170
reader.read_regex(_comment)

‎tests/test_main.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,3 +737,22 @@ def test_dotenv_values_file_stream(dotenv_path):
737737
result = dotenv.dotenv_values(stream=f)
738738

739739
assert result == {"a": "b"}
740+
741+
742+
@pytest.mark.parametrize(
743+
"string,expected",
744+
[
745+
("KEY= # comment", {"KEY": ""}),
746+
("KEY= # comment", {"KEY": ""}),
747+
("KEY=val # comment", {"KEY": "val"}),
748+
("KEY=a#b", {"KEY": "a#b"}),
749+
("KEY=#novalue", {"KEY": "#novalue"}),
750+
("KEY=# # comment", {"KEY": "#"}),
751+
("KEY=\t# comment", {"KEY": ""}),
752+
("KEY= # comment\nOTHER=val", {"KEY": "", "OTHER": "val"}),
753+
],
754+
)
755+
def test_dotenv_values_empty_value_with_inline_comment(string, expected):
756+
result = dotenv.dotenv_values(stream=io.StringIO(string))
757+
758+
assert result == expected

‎tests/test_parser.py‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,78 @@
119119
)
120120
],
121121
),
122+
(
123+
"a= #b",
124+
[
125+
Binding(
126+
key="a",
127+
value="",
128+
original=Original(string="a= #b", line=1),
129+
error=False,
130+
)
131+
],
132+
),
133+
(
134+
"a= # b",
135+
[
136+
Binding(
137+
key="a",
138+
value="",
139+
original=Original(string="a= # b", line=1),
140+
error=False,
141+
)
142+
],
143+
),
144+
(
145+
"a=#b",
146+
[
147+
Binding(
148+
key="a",
149+
value="#b",
150+
original=Original(string="a=#b", line=1),
151+
error=False,
152+
)
153+
],
154+
),
155+
(
156+
"a=# # comment",
157+
[
158+
Binding(
159+
key="a",
160+
value="#",
161+
original=Original(string="a=# # comment", line=1),
162+
error=False,
163+
)
164+
],
165+
),
166+
(
167+
"a=\t#c",
168+
[
169+
Binding(
170+
key="a",
171+
value="",
172+
original=Original(string="a=\t#c", line=1),
173+
error=False,
174+
)
175+
],
176+
),
177+
(
178+
"a= #c\nd=e",
179+
[
180+
Binding(
181+
key="a",
182+
value="",
183+
original=Original(string="a= #c\n", line=1),
184+
error=False,
185+
),
186+
Binding(
187+
key="d",
188+
value="e",
189+
original=Original(string="d=e", line=2),
190+
error=False,
191+
),
192+
],
193+
),
122194
(
123195
"a=b c",
124196
[

0 commit comments

Comments
 (0)