Skip to content

Commit 9714288

Browse files
committed
Fix array item removal
1 parent 1a3085c commit 9714288

File tree

3 files changed

+86
-9
lines changed

3 files changed

+86
-9
lines changed

tests/test_items.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,3 +1019,43 @@ def test_removal_of_arrayitem_with_extra_whitespace():
10191019
docstr = doc.as_string()
10201020
parse(docstr)
10211021
assert docstr == expected
1022+
1023+
1024+
def test_badly_formatted_array_and_item_removal():
1025+
# fmt: off
1026+
expected = """
1027+
x = [
1028+
'0'#a
1029+
,#b
1030+
1031+
# comment
1032+
'1' #c
1033+
, #d
1034+
# another comment
1035+
'2'
1036+
# yet another comment
1037+
,'3', # f
1038+
# comments here
1039+
'4'#g
1040+
# comments there
1041+
,'5' #h
1042+
# comments everywhere
1043+
# so many comments
1044+
,'6' ,
1045+
# you get a comment
1046+
# you get a comment
1047+
'7' ,#j
1048+
# everybody gets a comment!!!
1049+
"8"#c
1050+
,"9",
1051+
"10"
1052+
]
1053+
"""
1054+
# fmt: on
1055+
assert expected == parse(expected).as_string()
1056+
for i in range(11):
1057+
doc = parse(expected)
1058+
x = doc["x"]
1059+
assert isinstance(x, Array)
1060+
x.remove(str(i))
1061+
parse(doc.as_string())

tomlkit/items.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1138,11 +1138,13 @@ def _group_values(self, value: list[Item]) -> list[_ArrayItemGroup]:
11381138
"""Group the values into (indent, value, comma, comment) tuples"""
11391139
groups = []
11401140
this_group = _ArrayItemGroup()
1141+
start_new_group = False
11411142
for item in value:
11421143
if isinstance(item, Whitespace):
1143-
if "," not in item.s:
1144+
if "," not in item.s or start_new_group:
11441145
groups.append(this_group)
11451146
this_group = _ArrayItemGroup(indent=item)
1147+
start_new_group = False
11461148
else:
11471149
if this_group.value is None:
11481150
# when comma is met and no value is provided, add a dummy Null
@@ -1152,6 +1154,8 @@ def _group_values(self, value: list[Item]) -> list[_ArrayItemGroup]:
11521154
if this_group.value is None:
11531155
this_group.value = Null()
11541156
this_group.comment = item
1157+
# Comments are the last item in a group.
1158+
start_new_group = True
11551159
elif this_group.value is None:
11561160
this_group.value = item
11571161
else:
@@ -1399,6 +1403,7 @@ def __delitem__(self, key: int | slice):
13991403
if not isinstance(key, slice):
14001404
raise IndexError("list index out of range") from e
14011405
else:
1406+
group_rm = self._value[idx]
14021407
del self._value[idx]
14031408
if (
14041409
idx == 0
@@ -1408,6 +1413,42 @@ def __delitem__(self, key: int | slice):
14081413
):
14091414
# Remove the indentation of the first item if not newline
14101415
self._value[idx].indent = None
1416+
comma_in_indent = (
1417+
group_rm.indent is not None and "," in group_rm.indent.s
1418+
)
1419+
comma_in_comma = group_rm.comma is not None and "," in group_rm.comma.s
1420+
# If the removed group had both commas, add one to the next one.
1421+
if comma_in_indent and comma_in_comma:
1422+
group = self._value[idx] if len(self._value) > idx else None
1423+
if group is not None:
1424+
if group.indent is None:
1425+
group.indent = Whitespace(",")
1426+
elif "," not in group.indent.s:
1427+
# Insert the comma after the newline
1428+
try:
1429+
newline_index = group.indent.s.index("\n")
1430+
group.indent._s = (
1431+
group.indent.s[: newline_index + 1]
1432+
+ ","
1433+
+ group.indent.s[newline_index + 1 :]
1434+
)
1435+
except ValueError:
1436+
group.indent._s = "," + group.indent.s
1437+
# If the removed group did not have any commas, remove the next comma found
1438+
elif not comma_in_indent and not comma_in_comma:
1439+
for j in range(idx, len(self._value)):
1440+
group = self._value[j]
1441+
if group.indent is not None and "," in group.indent.s:
1442+
group.indent._s = group.indent.s.replace(",", "", 1)
1443+
break
1444+
# If the removed group had a newline and the next one doesn't, add one.
1445+
if group_rm.indent is not None and "\n" in group_rm.indent.s:
1446+
group = self._value[idx] if len(self._value) > idx else None
1447+
if group is not None:
1448+
if group.indent is None:
1449+
group.indent = Whitespace("\n")
1450+
elif "\n" not in group.indent.s:
1451+
group.indent._s = "\n" + group.indent.s
14111452
if len(self._value) > 0:
14121453
v = self._value[-1]
14131454
if not v.is_whitespace():

tomlkit/parser.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -595,15 +595,11 @@ def _parse_array(self) -> Array:
595595
# consume comma
596596
if prev_value and self._current == ",":
597597
self.inc(exception=UnexpectedEofError)
598-
# Check if the previous item is Whitespace
599-
if isinstance(elems[-1], Whitespace) and " " in elems[-1].s:
600-
# Preserve the previous whitespace
601-
comma = Whitespace(elems[-1].s + ",")
602-
# Remove the replaced item
603-
del elems[-1]
598+
# If the previous item is Whitespace, add to it
599+
if isinstance(elems[-1], Whitespace):
600+
elems[-1]._s = elems[-1].s + ","
604601
else:
605-
comma = Whitespace(",")
606-
elems.append(comma)
602+
elems.append(Whitespace(","))
607603
prev_value = False
608604
continue
609605

0 commit comments

Comments
 (0)