tomlkit icon indicating copy to clipboard operation
tomlkit copied to clipboard

out of order sections causing issues

Open abn opened this issue 2 years ago • 5 comments

When there are sections defined out of order, it seems tomlkit does not like it. Original issue was reported at https://github.com/python-poetry/poetry/issues/4718.

The following code runs without issues, however does not modify the toml. Using content.value_insert_after() causes AttributeError: 'dict' object has no attribute '_insert_after'.

If we remove build-system from the toml, the code below raises AttributeError: 'Table' object has no attribute '_insert_after'. However using content.value succeeds with the right results.

reproducer.py

import tomlkit


TOML = tomlkit.parse("""\
[tool.poetry]
name = "foobar"
version = "0.1.0"
description = ""
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.plugins]
""")


if __name__ == '__main__':
    content = TOML["tool"]["poetry"]
    content._insert_after("dependencies", "group", tomlkit.table(is_super_table=True))
    content["group"]["one"] = tomlkit.table(is_super_table=True)
    content["group"]["one"]["dependencies"] = tomlkit.table()
    print(TOML.as_string())

abn avatar May 25 '22 10:05 abn

Here is a test case that reproduces the issue.

def test_string_output_order_is_preserved_for_out_of_order_tables_with_insert_after():
    content_upper = """
[tool.poetry]
name = "foo"

[tool.poetry.dependencies]
python = "^3.6"
"""
    content_lower = """
[build-system]
requires = ["poetry-core"]
backend = "poetry.core.masonry.api"

[tool.poetry.build]
"""

    content_added = """
[tool.poetry.group.bar.dependencies]"""

    doc = parse(content_upper + content_lower)
    doc["tool"]["poetry"].value._insert_after(
        "dependencies", "group", tomlkit.table(True)
    )

    groups = doc["tool"]["poetry"]["group"]
    groups["bar"] = tomlkit.table(True)
    groups["bar"]["dependencies"] = tomlkit.table()

    assert doc.as_string() == content_upper + content_added + content_lower

abn avatar May 25 '22 19:05 abn

@frostming any chance I can get a pointer on where to fix this? Happy to do the leg work.

abn avatar May 27 '22 22:05 abn

You are trying to get the DOM element(A Container in tomlkit) of the table via .value while for a OutOfOrderTableProxy, the .value returns an intermediate helper Container that is created when building the proxy, hence any modification won't reflect to the original document.

To fix it, you need to make the modification on one of the underlying tables that are combined by the OutOfOrderTableProxy. See the example here. However, that needs to add those underscored methods to both OutOfOrderTableProxy, Table, and perhaps InlineTable.

frostming avatar May 30 '22 09:05 frostming

I'm having trouble following the example here. Is there any more documentation or examples on how to resolve these out of order problems?

I'm trying to update a tool.<TOOL_NAME> section but I can't seem to get it right.

Desired

[tool.ruff]
target-version = "py38"
line-length = 120
lint.select = ["F", "ASYNC", "RUFF", "B", "S", "PTH", "W", "E"]
lint.ignore = ["W191", "E111"]

Actual

[tool.ruff]
target-version = "py38"
line-length = 120
[tool.ruff.lint]
tool.ruff.lint.select = ["F", "ASYNC", "RUFF", "B", "S", "PTH", "W", "E"]
tool.ruff.lint.ignore = ["W191", "E111"]

Kilo59 avatar Mar 31 '24 12:03 Kilo59

I'm having trouble following the example here.

Sorry, what code you are trying?

frostming avatar Apr 01 '24 00:04 frostming