diff --git a/tests/test_toml_document.py b/tests/test_toml_document.py index 7ba61f5..d5440a8 100644 --- a/tests/test_toml_document.py +++ b/tests/test_toml_document.py @@ -643,6 +643,13 @@ def test_valid_out_of_order_independent_tables() -> None: assert doc.as_string() == "[a]\nx=1\n[zz]\n[a.b]\nc=1\n" +def test_valid_nested_out_of_order_table_after_unrelated_table() -> None: + content = "[a]\n[a.b.c]\n[a.b]\n[[zz]]\n[a.b.d]\n" + doc = parse(content) + assert doc.unwrap() == {"a": {"b": {"c": {}, "d": {}}}, "zz": [{}]} + assert doc.as_string() == content + + def test_set_value_on_out_of_order_table_with_empty_concrete_part() -> None: # A super table defined after its sub-table (the "defining a super-table # afterward is ok" spec example) leaves an empty concrete `[x]` part. diff --git a/tomlkit/container.py b/tomlkit/container.py index 8ff30d9..7b40395 100644 --- a/tomlkit/container.py +++ b/tomlkit/container.py @@ -423,19 +423,24 @@ def _validate_table_candidate(self, current: Table, candidate: Table) -> None: continue if k in current.value._map: - existing = current.value.item(k) - if isinstance(existing, (Table, AoT)) != isinstance(v, (Table, AoT)): - raise KeyAlreadyPresent(k) - if k.is_dotted(): - raise TOMLKitError("Redefinition of an existing table") - if isinstance(existing, Table) and isinstance(v, Table): - if not existing.is_super_table() and not v.is_super_table(): - # Both sides are concrete `[table]` definitions of the - # same name; the table is declared twice. + index = current.value._map[k] + indices = index if isinstance(index, tuple) else (index,) + for i in indices: + existing = current.value._body[i][1] + if isinstance(existing, (Table, AoT)) != isinstance( + v, (Table, AoT) + ): raise KeyAlreadyPresent(k) - # One side is still an implicit/super table, so a duplicate - # (if any) is nested deeper - keep checking the subtree. - self._validate_table_candidate(existing, v) + if k.is_dotted(): + raise TOMLKitError("Redefinition of an existing table") + if isinstance(existing, Table) and isinstance(v, Table): + if not existing.is_super_table() and not v.is_super_table(): + # Both sides are concrete `[table]` definitions of the + # same name; the table is declared twice. + raise KeyAlreadyPresent(k) + # One side is still an implicit/super table, so a duplicate + # (if any) is nested deeper - keep checking the subtree. + self._validate_table_candidate(existing, v) continue if not k.is_dotted():