Skip to content
Open
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
9 changes: 9 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,17 @@
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
]

# Resolve references to the standard library and other projects, so that
# annotations such as collections.abc.Mapping or datetime.datetime link to
# their documentation instead of producing "reference target not found"
# warnings under `sphinx-build -n`.
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
}

# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]

Expand Down
32 changes: 32 additions & 0 deletions tests/test_toml_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,38 @@ 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_out_of_order_child_split_by_unrelated_table() -> None:
# https://github.com/python-poetry/tomlkit/issues/571
# An out-of-order child, its concrete parent declared afterwards, and a
# later sibling child separated by an unrelated table. tomllib accepts
# this, and so did tomlkit 0.13.3/0.14.0/0.15.0.
source = """\
[tool.ruff]
[tool.ruff.lint.a]
[tool.ruff.lint]
[[tool.poetry.source]]
[tool.ruff.lint.b]
"""
doc = parse(source)
assert doc.unwrap() == {
"tool": {
"ruff": {
"lint": {"a": {}, "b": {}},
},
"poetry": {"source": [{}]},
},
}
assert doc.as_string() == source


def test_out_of_order_child_split_at_depth() -> None:
# Same shape, deeper and without the array-of-tables in between.
source = "[a.b]\n[a.b.c.d]\n[a.b.c]\n[z]\n[a.b.c.e]\n"
doc = parse(source)
assert doc.unwrap() == {"a": {"b": {"c": {"d": {}, "e": {}}}}, "z": {}}
assert doc.as_string() == source


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.
Expand Down
7 changes: 7 additions & 0 deletions tomlkit/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,13 @@ def _validate_table_candidate(self, current: Table, candidate: Table) -> None:

if k in current.value._map:
existing = current.value.item(k)
# An OutOfOrderTableProxy stands for one or more tables whose
# definitions are spread through the document; it is not a
# `Table` instance, so the isinstance comparison below would
# wrongly report a type conflict for a valid out-of-order
# document. Its contents are already validated by the proxy.
if isinstance(existing, OutOfOrderTableProxy):
continue
if isinstance(existing, (Table, AoT)) != isinstance(v, (Table, AoT)):
raise KeyAlreadyPresent(k)
if k.is_dotted():
Expand Down
Loading