Skip to content

Commit

Permalink
Merge pull request #168 from MrGreenTea/master
Browse files Browse the repository at this point in the history
Fix values similar to booleans being incorrectly parsed to booleans
  • Loading branch information
frostming authored Jan 31, 2022
2 parents 7b45066 + c711380 commit 193b859
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 7 deletions.
73 changes: 73 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,76 @@ def test_add_dotted_key():
table = tomlkit.table()
table.add(tomlkit.key(["foo", "bar"]), 1)
assert table.as_string() == "foo.bar = 1\n"


@pytest.mark.parametrize(
("raw", "expected"),
[
("true", True),
("false", False),
],
)
def test_value_parses_boolean(raw, expected):
parsed = tomlkit.value(raw)
assert parsed == expected


@pytest.mark.parametrize(
"raw", ["t", "f", "tru", "fals", "test", "friend", "truthy", "falsify"]
)
def test_value_rejects_values_looking_like_bool_at_start(raw):
"""Reproduces https://github.com/sdispater/tomlkit/issues/165"""
with pytest.raises(tomlkit.exceptions.ParseError):
tomlkit.value(raw)


@pytest.mark.parametrize(
"raw",
[
"truee",
"truely",
"true-thoughts",
"true_hip_hop",
],
)
def test_value_rejects_values_having_true_prefix(raw):
"""Values that have ``true`` or ``false`` as prefix but then have additional chars are rejected."""
with pytest.raises(tomlkit.exceptions.ParseError):
tomlkit.value(raw)


@pytest.mark.parametrize(
"raw",
[
"falsee",
"falsely",
"false-ideas",
"false_prophet",
],
)
def test_value_rejects_values_having_false_prefix(raw):
"""Values that have ``true`` or ``false`` as prefix but then have additional chars are rejected."""
with pytest.raises(tomlkit.exceptions.ParseError):
tomlkit.value(raw)


@pytest.mark.parametrize(
"raw",
[
'"foo"1.2',
"truefalse",
"1.0false",
"100true",
"truetrue",
"falsefalse",
"1.2.3.4",
"[][]",
"{a=[][]}[]",
"true[]",
"false{a=1}",
],
)
def test_value_rejects_values_with_appendage(raw):
"""Values that appear valid at the beginning but leave chars unparsed are rejected."""
with pytest.raises(tomlkit.exceptions.ParseError):
tomlkit.value(raw)
7 changes: 6 additions & 1 deletion tomlkit/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from ._utils import parse_rfc3339
from .container import Container
from .exceptions import UnexpectedCharError
from .items import AoT
from .items import Array
from .items import Bool
Expand Down Expand Up @@ -232,7 +233,11 @@ def value(raw: str) -> _Item:
>>> value("[1, 2, 3]")
[1, 2, 3]
"""
return Parser(raw)._parse_value()
parser = Parser(raw)
v = parser._parse_value()
if not parser.end():
raise parser.parse_error(UnexpectedCharError, char=parser._current)
return v


def key_value(src: str) -> Tuple[Key, _Item]:
Expand Down
6 changes: 3 additions & 3 deletions tomlkit/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ def mark(self) -> None:
"""
self._src.mark()

def parse_error(self, exception=ParseError, *args):
def parse_error(self, exception=ParseError, *args, **kwargs):
"""
Creates a generic "parse error" at the current position.
"""
return self._src.parse_error(exception, *args)
return self._src.parse_error(exception, *args, **kwargs)

def parse(self) -> TOMLDocument:
body = TOMLDocument(True)
Expand Down Expand Up @@ -1082,7 +1082,7 @@ def _peek(self, n: int) -> str:
with self._state(restore=True):
buf = ""
for _ in range(n):
if self._current not in " \t\n\r#,]}":
if self._current not in " \t\n\r#,]}" + self._src.EOF:
buf += self._current
self.inc()
continue
Expand Down
9 changes: 6 additions & 3 deletions tomlkit/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def consume(self, chars, min=0, max=-1):

# failed to consume minimum number of characters
if min > 0:
self.parse_error(UnexpectedCharError, self.current)
raise self.parse_error(UnexpectedCharError, self.current)

def end(self) -> bool:
"""
Expand All @@ -162,14 +162,17 @@ def mark(self) -> None:
self._marker = self._idx

def parse_error(
self, exception: Type[ParseError] = ParseError, *args: Any
self,
exception: Type[ParseError] = ParseError,
*args: Any,
**kwargs: Any,
) -> ParseError:
"""
Creates a generic "parse error" at the current position.
"""
line, col = self._to_linecol()

return exception(line, col, *args)
return exception(line, col, *args, **kwargs)

def _to_linecol(self) -> Tuple[int, int]:
cur = 0
Expand Down

0 comments on commit 193b859

Please sign in to comment.