Skip to content

Commit 7b172fe

Browse files
committed
Fix parsing of unquoted values with two spaces
If a value is unquoted and has two or more adjacent spaces (like in `a=b c`), the parser would detect an error. This commit fixes that. Tabs and other whitespace characters are now also considered like space characters in this case and I added relevant test cases.
1 parent 6ca2e2a commit 7b172fe

File tree

3 files changed

+35
-18
lines changed

3 files changed

+35
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1919

2020
### Fixed
2121

22-
- Fix potentially empty expanded value for duplicate key (#260 by [@bbc]).
22+
- Fix potentially empty expanded value for duplicate key (#260 by [@bbc2]).
2323
- Fix import error on Python 3.5.0 and 3.5.1 (#267 by [@gongqingkui]).
24+
- Fix parsing of unquoted values containing several adjacent space or tab characters
25+
(#277 by [@bbc2], review by [@x-yuri]).
2426

2527
## [0.14.0] - 2020-07-03
2628

@@ -226,6 +228,7 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
226228
[@theskumar]: https://github.com/theskumar
227229
[@ulyssessouza]: https://github.com/ulyssessouza
228230
[@venthur]: https://github.com/venthur
231+
[@x-yuri]: https://github.com/x-yuri
229232
[@yannham]: https://github.com/yannham
230233

231234
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v0.14.0...HEAD

src/dotenv/parser.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def make_regex(string, extra_flags=0):
2424
_equal_sign = make_regex(r"(=[^\S\r\n]*)")
2525
_single_quoted_value = make_regex(r"'((?:\\'|[^'])*)'")
2626
_double_quoted_value = make_regex(r'"((?:\\"|[^"])*)"')
27-
_unquoted_value_part = make_regex(r"([^ \r\n]*)")
27+
_unquoted_value = make_regex(r"([^\r\n]*)")
2828
_comment = make_regex(r"(?:[^\S\r\n]*#[^\r\n]*)?")
2929
_end_of_line = make_regex(r"[^\S\r\n]*(?:\r\n|\n|\r|$)")
3030
_rest_of_line = make_regex(r"[^\r\n]*(?:\r|\n|\r\n)?")
@@ -167,14 +167,8 @@ def parse_key(reader):
167167

168168
def parse_unquoted_value(reader):
169169
# type: (Reader) -> Text
170-
value = u""
171-
while True:
172-
(part,) = reader.read_regex(_unquoted_value_part)
173-
value += part
174-
after = reader.peek(2)
175-
if len(after) < 2 or after[0] in u"\r\n" or after[1] in u" #\r\n":
176-
return value
177-
value += reader.read(2)
170+
(part,) = reader.read_regex(_unquoted_value)
171+
return re.sub(r"\s+#.*", "", part).rstrip()
178172

179173

180174
def parse_value(reader):

tests/test_parser.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,40 @@
1919
(u"# a=b", [Binding(key=None, value=None, original=Original(string=u"# a=b", line=1), error=False)]),
2020
(u"a=b#c", [Binding(key=u"a", value=u"b#c", original=Original(string=u"a=b#c", line=1), error=False)]),
2121
(
22-
u'a=b # comment',
23-
[Binding(key=u"a", value=u"b", original=Original(string=u"a=b # comment", line=1), error=False)],
22+
u'a=b #c',
23+
[Binding(key=u"a", value=u"b", original=Original(string=u"a=b #c", line=1), error=False)],
2424
),
2525
(
26-
u"a=b space ",
27-
[Binding(key=u"a", value=u"b space", original=Original(string=u"a=b space ", line=1), error=False)],
26+
u'a=b\t#c',
27+
[Binding(key=u"a", value=u"b", original=Original(string=u"a=b\t#c", line=1), error=False)],
2828
),
2929
(
30-
u"a='b space '",
31-
[Binding(key=u"a", value=u"b space ", original=Original(string=u"a='b space '", line=1), error=False)],
30+
u"a=b c",
31+
[Binding(key=u"a", value=u"b c", original=Original(string=u"a=b c", line=1), error=False)],
3232
),
3333
(
34-
u'a="b space "',
35-
[Binding(key=u"a", value=u"b space ", original=Original(string=u'a="b space "', line=1), error=False)],
34+
u"a=b\tc",
35+
[Binding(key=u"a", value=u"b\tc", original=Original(string=u"a=b\tc", line=1), error=False)],
36+
),
37+
(
38+
u"a=b c",
39+
[Binding(key=u"a", value=u"b c", original=Original(string=u"a=b c", line=1), error=False)],
40+
),
41+
(
42+
u"a=b\u00a0 c",
43+
[Binding(key=u"a", value=u"b\u00a0 c", original=Original(string=u"a=b\u00a0 c", line=1), error=False)],
44+
),
45+
(
46+
u"a=b c ",
47+
[Binding(key=u"a", value=u"b c", original=Original(string=u"a=b c ", line=1), error=False)],
48+
),
49+
(
50+
u"a='b c '",
51+
[Binding(key=u"a", value=u"b c ", original=Original(string=u"a='b c '", line=1), error=False)],
52+
),
53+
(
54+
u'a="b c "',
55+
[Binding(key=u"a", value=u"b c ", original=Original(string=u'a="b c "', line=1), error=False)],
3656
),
3757
(
3858
u"export export_a=1",

0 commit comments

Comments
 (0)