Skip to content
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
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2.3.1
=====

* fix quadratic parse time for values with many continuation lines (#78, regarding #77)
* internal: ``iniconfig._parse.ParsedLine.value`` is now a list of lines

2.3.0
=====

Expand Down
19 changes: 6 additions & 13 deletions src/iniconfig/_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ParsedLine(NamedTuple):
lineno: int
section: str | None
name: str | None
value: str | None
value: list[str] | None


def parse_ini_data(
Expand Down Expand Up @@ -56,7 +56,7 @@ def parse_ini_data(
if name in sections_data[section]:
raise ParseError(path, lineno, f"duplicate name {name!r}")
assert value is not None
sections_data[section][name] = value
sections_data[section][name] = "\n".join(value)

return sections_data, sources

Expand All @@ -76,7 +76,7 @@ def parse_lines(
)
# new value
if name is not None and data is not None:
result.append(ParsedLine(lineno, section, name, data))
result.append(ParsedLine(lineno, section, name, [data] if data else []))
# new section
elif name is not None and data is None:
if not name:
Expand All @@ -85,17 +85,10 @@ def parse_lines(
result.append(ParsedLine(lineno, section, None, None))
# continuation
elif name is None and data is not None:
if not result:
value = result[-1].value if result else None
if value is None:
raise ParseError(path, lineno, "unexpected value continuation")
last = result.pop()
if last.name is None:
raise ParseError(path, lineno, "unexpected value continuation")

if last.value:
last = last._replace(value=f"{last.value}\n{data}")
else:
last = last._replace(value=data)
result.append(last)
value.append(data)
return result


Expand Down
32 changes: 21 additions & 11 deletions testing/test_iniconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,46 @@

check_tokens: dict[str, tuple[str, list[PL]]] = {
"section": ("[section]", [PL(0, "section", None, None)]),
"value": ("value = 1", [PL(0, None, "value", "1")]),
"value": ("value = 1", [PL(0, None, "value", ["1"])]),
"value in section": (
"[section]\nvalue=1",
[PL(0, "section", None, None), PL(1, "section", "value", "1")],
[PL(0, "section", None, None), PL(1, "section", "value", ["1"])],
),
"empty value": ("value =", [PL(0, None, "value", [])]),
"value with continuation": (
"names =\n Alice\n Bob",
[PL(0, None, "names", "Alice\nBob")],
[PL(0, None, "names", ["Alice", "Bob"])],
),
"value with aligned continuation": (
"names = Alice\n Bob",
[PL(0, None, "names", "Alice\nBob")],
[PL(0, None, "names", ["Alice", "Bob"])],
),
"continuations on several values": (
"a = 1\n 2\n\n 3\n[s]\nb =\n x\n y\nc = z",
[
PL(0, None, "a", ["1", "2", "3"]),
PL(4, "s", None, None),
PL(5, "s", "b", ["x", "y"]),
PL(8, "s", "c", ["z"]),
],
),
"blank line": (
"[section]\n\nvalue=1",
[PL(0, "section", None, None), PL(2, "section", "value", "1")],
[PL(0, "section", None, None), PL(2, "section", "value", ["1"])],
),
"comment": ("# comment", []),
"comment on value": ("value = 1", [PL(0, None, "value", "1")]),
"comment on value": ("value = 1", [PL(0, None, "value", ["1"])]),
"comment on section": ("[section] #comment", [PL(0, "section", None, None)]),
"comment2": ("; comment", []),
"comment2 on section": ("[section] ;comment", [PL(0, "section", None, None)]),
"pseudo section syntax in value": (
"name = value []",
[PL(0, None, "name", "value []")],
[PL(0, None, "name", ["value []"])],
),
"assignment in value": ("value = x = 3", [PL(0, None, "value", "x = 3")]),
"use of colon for name-values": ("name: y", [PL(0, None, "name", "y")]),
"use of colon without space": ("value:y=5", [PL(0, None, "value", "y=5")]),
"equality gets precedence": ("value=xyz:5", [PL(0, None, "value", "xyz:5")]),
"assignment in value": ("value = x = 3", [PL(0, None, "value", ["x = 3"])]),
"use of colon for name-values": ("name: y", [PL(0, None, "name", ["y"])]),
"use of colon without space": ("value:y=5", [PL(0, None, "value", ["y=5"])]),
"equality gets precedence": ("value=xyz:5", [PL(0, None, "value", ["xyz:5"])]),
}


Expand Down
Loading