Skip to content

Commit

Permalink
fix: Significant slowdown on nested tables depending on syntax (#324)
Browse files Browse the repository at this point in the history
  • Loading branch information
frostming committed Nov 15, 2023
1 parent e9ccbe7 commit 238fec1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 23 deletions.
43 changes: 22 additions & 21 deletions tomlkit/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,19 @@ def _get_last_index_before_table(self) -> int:
last_index = i
return last_index + 1

def append(self, key: Key | str | None, item: Item) -> Container:
def _validate_out_of_order_table(self, key: SingleKey | None = None) -> None:
if key is None:
for k in self._map:
assert k is not None
self._validate_out_of_order_table(k)
return
if key not in self._map or not isinstance(self._map[key], tuple):
return
OutOfOrderTableProxy(self, self._map[key])

def append(
self, key: Key | str | None, item: Item, validate: bool = True
) -> Container:
"""Similar to :meth:`add` but both key and value must be given."""
if not isinstance(key, Key) and key is not None:
key = SingleKey(key)
Expand Down Expand Up @@ -229,8 +241,8 @@ def append(self, key: Key | str | None, item: Item) -> Container:
else:
self._raw_append(key, item)

# Building a temporary proxy to check for errors
OutOfOrderTableProxy(self, self._map[key])
if validate:
self._validate_out_of_order_table(key)

return self

Expand Down Expand Up @@ -288,7 +300,7 @@ def append(self, key: Key | str | None, item: Item) -> Container:
self._raw_append(key, item)
return self

def _raw_append(self, key: Key, item: Item) -> None:
def _raw_append(self, key: Key | None, item: Item) -> None:
if key in self._map:
current_idx = self._map[key]
if not isinstance(current_idx, tuple):
Expand All @@ -299,7 +311,7 @@ def _raw_append(self, key: Key, item: Item) -> None:
raise KeyAlreadyPresent(key)

self._map[key] = current_idx + (len(self._body),)
else:
elif key is not None:
self._map[key] = len(self._body)

self._body.append((key, item))
Expand Down Expand Up @@ -607,21 +619,8 @@ def __iter__(self) -> Iterator[str]:

# Dictionary methods
def __getitem__(self, key: Key | str) -> Item | Container:
if not isinstance(key, Key):
key = SingleKey(key)

idx = self._map.get(key)
if idx is None:
raise NonExistentKey(key)

if isinstance(idx, tuple):
# The item we are getting is an out of order table
# so we need a proxy to retrieve the proper objects
# from the parent container
return OutOfOrderTableProxy(self, idx)

item = self._body[idx][1]
if item.is_boolean():
item = self.item(key)
if isinstance(item, Item) and item.is_boolean():
return item.value

return item
Expand Down Expand Up @@ -800,11 +799,13 @@ def __init__(self, container: Container, indices: tuple[int]) -> None:
self._tables.append(item)
table_idx = len(self._tables) - 1
for k, v in item.value.body:
self._internal_container.append(k, v)
self._internal_container.append(k, v, validate=False)
self._tables_map[k] = table_idx
if k is not None:
dict.__setitem__(self, k.key, v)

self._internal_container._validate_out_of_order_table()

def unwrap(self) -> str:
return self._internal_container.unwrap()

Expand Down
2 changes: 1 addition & 1 deletion tomlkit/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -1617,7 +1617,7 @@ def raw_append(self, key: Key | str | None, _item: Any) -> Table:
if not isinstance(_item, Item):
_item = item(_item)

self._value.append(key, _item)
self._value.append(key, _item, validate=False)

if isinstance(key, Key):
key = next(iter(key)).key
Expand Down
2 changes: 1 addition & 1 deletion tomlkit/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ def _parse_table(
InternalParserError,
"_parse_item() returned None on a non-bracket character.",
)

table.value._validate_out_of_order_table()
if isinstance(result, Null):
result = table

Expand Down

0 comments on commit 238fec1

Please sign in to comment.