Skip to content

Commit cc89aca

Browse files
authored
Fix the way table names are parsed (#76)
1 parent de23e48 commit cc89aca

File tree

4 files changed

+94
-12
lines changed

4 files changed

+94
-12
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"Special \"table\"": {
3+
"foo": "bar"
4+
},
5+
"BJ's Restaurant": {
6+
"account": "dining"
7+
},
8+
"]": {
9+
"foo": 1
10+
},
11+
"[bracket]": {
12+
"bar": 2
13+
},
14+
"a": {
15+
"b.c": {
16+
"d": {
17+
"baz": 3
18+
}
19+
}
20+
}
21+
}

tests/examples/table_names_with_string_delimiters.toml renamed to tests/examples/table_names.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,12 @@ foo = "bar"
33

44
["BJ's Restaurant"]
55
account = "dining"
6+
7+
["]"]
8+
foo = 1
9+
10+
[ "[bracket]" ]
11+
bar = 2
12+
13+
[ a . "b.c" . d ]
14+
baz = 3

tests/test_api.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ def json_serial(obj):
5353
"newline_in_strings",
5454
"preserve_quotes_in_string",
5555
"string_slash_whitespace_newline",
56-
"table_names_with_string_delimiters",
56+
"table_names",
5757
],
5858
)
5959
def test_parse_can_parse_valid_toml_files(example, example_name):
6060
assert isinstance(parse(example(example_name)), TOMLDocument)
6161
assert isinstance(loads(example(example_name)), TOMLDocument)
6262

6363

64-
@pytest.mark.parametrize("example_name", ["0.5.0", "pyproject"])
64+
@pytest.mark.parametrize("example_name", ["0.5.0", "pyproject", "table_names"])
6565
def test_parsed_document_are_properly_json_representable(
6666
example, json_example, example_name
6767
):
@@ -111,6 +111,7 @@ def test_parse_raises_errors_for_invalid_toml_files(
111111
"pyproject",
112112
"0.5.0",
113113
"test",
114+
"table_names",
114115
],
115116
)
116117
def test_original_string_and_dumped_string_are_equal(example, example_name):

tomlkit/parser.py

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ def _split_table_name(self, name): # type: (str) -> Generator[Key]
201201
in_name = False
202202
current = ""
203203
t = KeyType.Bare
204-
for c in name:
204+
parts = 0
205+
for c in name.strip():
205206
c = TOMLChar(c)
206207

207208
if c == ".":
@@ -212,7 +213,8 @@ def _split_table_name(self, name): # type: (str) -> Generator[Key]
212213
if not current:
213214
raise self.parse_error()
214215

215-
yield Key(current, t=t, sep="")
216+
yield Key(current.strip(), t=t, sep="")
217+
parts += 1
216218

217219
current = ""
218220
t = KeyType.Bare
@@ -233,17 +235,35 @@ def _split_table_name(self, name): # type: (str) -> Generator[Key]
233235

234236
in_name = False
235237
else:
238+
if current and TOMLChar(current[-1]).is_spaces() and not parts:
239+
raise self.parse_error()
240+
236241
in_name = True
237242
t = KeyType.Literal if c == "'" else KeyType.Basic
238243

239244
continue
240245
elif in_name or c.is_bare_key_char():
246+
if (
247+
not in_name
248+
and current
249+
and TOMLChar(current[-1]).is_spaces()
250+
and not parts
251+
):
252+
raise self.parse_error()
253+
241254
current += c
255+
elif c.is_spaces():
256+
# A space is only valid at this point
257+
# if it's in between parts.
258+
# We store it for now and will check
259+
# later if it's valid
260+
current += c
261+
continue
242262
else:
243263
raise self.parse_error()
244264

245-
if current:
246-
yield Key(current, t=t, sep="")
265+
if current.strip():
266+
yield Key(current.strip(), t=t, sep="")
247267

248268
def _parse_item(self): # type: () -> Optional[Tuple[Optional[Key], Item]]
249269
"""
@@ -916,15 +936,46 @@ def _parse_table(
916936

917937
is_aot = True
918938

919-
# Key
939+
# Consume any whitespace
920940
self.mark()
921-
while self._current != "]" and self.inc():
922-
if self.end():
923-
raise self.parse_error(UnexpectedEofError)
924-
941+
while self._current.is_spaces() and self.inc():
925942
pass
926943

927-
name = self.extract()
944+
ws_prefix = self.extract()
945+
946+
# Key
947+
if self._current in [StringType.SLL.value, StringType.SLB.value]:
948+
delimiter = (
949+
StringType.SLL
950+
if self._current == StringType.SLL.value
951+
else StringType.SLB
952+
)
953+
name = self._parse_string(delimiter)
954+
name = "{delimiter}{name}{delimiter}".format(
955+
delimiter=delimiter.value, name=name
956+
)
957+
958+
self.mark()
959+
while self._current != "]" and self.inc():
960+
if self.end():
961+
raise self.parse_error(UnexpectedEofError)
962+
963+
pass
964+
965+
ws_suffix = self.extract()
966+
name += ws_suffix
967+
else:
968+
self.mark()
969+
while self._current != "]" and self.inc():
970+
if self.end():
971+
raise self.parse_error(UnexpectedEofError)
972+
973+
pass
974+
975+
name = self.extract()
976+
977+
name = ws_prefix + name
978+
928979
if not name.strip():
929980
raise self.parse_error(EmptyTableNameError)
930981

0 commit comments

Comments
 (0)