Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix values similar to booleans being incorrectly parsed to booleans #168

Merged
merged 4 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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