Skip to content

Commit 8fa9365

Browse files
authored
Merge branch 'python-poetry:master' into master
2 parents 0c45a51 + 832e855 commit 8fa9365

File tree

4 files changed

+116
-11
lines changed

4 files changed

+116
-11
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repos:
1515
args: [--py37-plus]
1616

1717
- repo: https://github.com/astral-sh/ruff-pre-commit
18-
rev: 'v0.9.2'
18+
rev: 'v0.11.10'
1919
hooks:
2020
- id: ruff
2121
args: [--fix, --exit-non-zero-on-fix, --show-fixes]

tests/test_items.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ def test_aot_unwrap():
129129
assert_is_ppo(vu, str)
130130

131131

132+
def test_aot_set_item():
133+
d = item(["A", {"b": "B"}, ["c", "D"]])
134+
d[0] = "C"
135+
assert isinstance(d[0], String)
136+
assert d[0] == "C"
137+
d[1]["b"] = "D"
138+
assert isinstance(d[1], InlineTable)
139+
assert d[1]["b"] == "D"
140+
d[0] = ["c", "C"]
141+
assert isinstance(d[0], Array)
142+
assert d[0][1] == "C"
143+
144+
132145
def test_time_unwrap():
133146
t = time(3, 8, 14)
134147
elementary_test(item(t), time)
@@ -1019,3 +1032,56 @@ def test_removal_of_arrayitem_with_extra_whitespace():
10191032
docstr = doc.as_string()
10201033
parse(docstr)
10211034
assert docstr == expected
1035+
1036+
1037+
def test_badly_formatted_array_and_item_removal():
1038+
expected = """
1039+
x = [
1040+
'0'#a
1041+
,#b
1042+
1043+
# comment
1044+
'1' #c
1045+
, #d
1046+
# another comment
1047+
'2'
1048+
# yet another comment
1049+
,'3', # f
1050+
# comments here
1051+
'4'#g
1052+
# comments there
1053+
,'5' #h
1054+
# comments everywhere
1055+
# so many comments
1056+
,'6' ,
1057+
# you get a comment
1058+
# you get a comment
1059+
'7' ,#j
1060+
# everybody gets a comment!!!
1061+
"8"#c
1062+
,"9", \n "10"
1063+
]
1064+
"""
1065+
assert expected == parse(expected).as_string()
1066+
for i in range(11):
1067+
doc = parse(expected)
1068+
x = doc["x"]
1069+
assert isinstance(x, Array)
1070+
x.remove(str(i))
1071+
parse(doc.as_string())
1072+
1073+
1074+
def test_array_item_removal_newline_restore_next():
1075+
expected = "x = [\n '0',\n '2'\n]"
1076+
1077+
docstr = "x = [\n '0',\n '1','2'\n]"
1078+
doc = parse(docstr)
1079+
doc["x"].remove("1")
1080+
assert doc.as_string() == expected
1081+
parse(doc.as_string())
1082+
1083+
docstr = "x = [\n '0',\n '1', '2'\n]"
1084+
doc = parse(docstr)
1085+
doc["x"].remove("1")
1086+
assert doc.as_string() == expected
1087+
parse(doc.as_string())

tomlkit/items.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,11 +1142,13 @@ def _group_values(self, value: list[Item]) -> list[_ArrayItemGroup]:
11421142
"""Group the values into (indent, value, comma, comment) tuples"""
11431143
groups = []
11441144
this_group = _ArrayItemGroup()
1145+
start_new_group = False
11451146
for item in value:
11461147
if isinstance(item, Whitespace):
1147-
if "," not in item.s:
1148+
if "," not in item.s or start_new_group:
11481149
groups.append(this_group)
11491150
this_group = _ArrayItemGroup(indent=item)
1151+
start_new_group = False
11501152
else:
11511153
if this_group.value is None:
11521154
# when comma is met and no value is provided, add a dummy Null
@@ -1156,6 +1158,8 @@ def _group_values(self, value: list[Item]) -> list[_ArrayItemGroup]:
11561158
if this_group.value is None:
11571159
this_group.value = Null()
11581160
this_group.comment = item
1161+
# Comments are the last item in a group.
1162+
start_new_group = True
11591163
elif this_group.value is None:
11601164
this_group.value = item
11611165
else:
@@ -1403,6 +1407,7 @@ def __delitem__(self, key: int | slice):
14031407
if not isinstance(key, slice):
14041408
raise IndexError("list index out of range") from e
14051409
else:
1410+
group_rm = self._value[idx]
14061411
del self._value[idx]
14071412
if (
14081413
idx == 0
@@ -1412,6 +1417,44 @@ def __delitem__(self, key: int | slice):
14121417
):
14131418
# Remove the indentation of the first item if not newline
14141419
self._value[idx].indent = None
1420+
comma_in_indent = (
1421+
group_rm.indent is not None and "," in group_rm.indent.s
1422+
)
1423+
comma_in_comma = group_rm.comma is not None and "," in group_rm.comma.s
1424+
if comma_in_indent and comma_in_comma:
1425+
# Removed group had both commas. Add one to the next group.
1426+
group = self._value[idx] if len(self._value) > idx else None
1427+
if group is not None:
1428+
if group.indent is None:
1429+
group.indent = Whitespace(",")
1430+
elif "," not in group.indent.s:
1431+
# Insert the comma after the newline
1432+
try:
1433+
newline_index = group.indent.s.index("\n")
1434+
group.indent._s = (
1435+
group.indent.s[: newline_index + 1]
1436+
+ ","
1437+
+ group.indent.s[newline_index + 1 :]
1438+
)
1439+
except ValueError:
1440+
group.indent._s = "," + group.indent.s
1441+
elif not comma_in_indent and not comma_in_comma:
1442+
# Removed group had no commas. Remove the next comma found.
1443+
for j in range(idx, len(self._value)):
1444+
group = self._value[j]
1445+
if group.indent is not None and "," in group.indent.s:
1446+
group.indent._s = group.indent.s.replace(",", "", 1)
1447+
break
1448+
if group_rm.indent is not None and "\n" in group_rm.indent.s:
1449+
# Restore the removed group's newline onto the next group
1450+
# if the next group does not have a newline.
1451+
# i.e. the two were on the same line
1452+
group = self._value[idx] if len(self._value) > idx else None
1453+
if group is not None and (
1454+
group.indent is None or "\n" not in group.indent.s
1455+
):
1456+
group.indent = group_rm.indent
1457+
14151458
if len(self._value) > 0:
14161459
v = self._value[-1]
14171460
if not v.is_whitespace():
@@ -1889,7 +1932,7 @@ def __getitem__(self, key):
18891932
return self._body[key]
18901933

18911934
def __setitem__(self, key: slice | int, value: Any) -> None:
1892-
raise NotImplementedError
1935+
self._body[key] = item(value, _parent=self)
18931936

18941937
def __delitem__(self, key: slice | int) -> None:
18951938
del self._body[key]

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)