Skip to content

rewrite new toml-data will has a new whitespace line #352

Closed

Description

@yanquer

rewrite toml data will has a new whitespace line.

eg toml:

toml

# xxx test


[env.pro1.rst]
    name = "x7"

[env2]
    name = 2

[env3]
    name = 3

modified with rewrite new tool data, like this

file_ = "test.toml"

def update_toml():
    with open(file_, "r") as f:
        t = tomlkit.load(f)

    t = merge_dicts(
        t,
        {'env': {'pro1': {'rst': {'name': "x7"}}}}
    )

    with open(file_, "w") as f:
        tomlkit.dump(t, f)

def merge_dicts(a: dict, b: dict):
    # ret = a.copy()
    ret = a

    for k, v in b.items():
        if k in a and isinstance(a[k], (dict, OrderedDict, Container)):
            ret[k] = merge_dicts(a[k], v)

    return ret

the result (has a new line after name = "x7")

# xxx test


[env.pro1.rst]
    name = "x7"


[env2]
    name = 2

[env3]
    name = 3

and if I edit in local with code

def merge_dicts(a: dict, b: dict):
    # ret = a.copy()
    return merge_dict_to_toml_local(a, b)


def merge_dict_to_toml_local(a: tomlkit.TOMLDocument, b: dict):

    for k, v in b.items():
        if k in a and isinstance(a[k], (dict, OrderedDict, Container)):
            merge_dict_to_toml_local(a[k], v)
        else:
            a[k] = v

There will be no more line.

I'm not sure if this is a bug, so I checked the source code.
in file tomlkit/container.py, line 703 with function _replace_at , it will add a whitespace-line where there is not has whitespace-line.
how check ? the end of tomlkit/container.py

def ends_with_whitespace(it: Any) -> bool:
    """Returns ``True`` if the given item ``it`` is a ``Table`` or ``AoT`` object
    ending with a ``Whitespace``.
    """
    return (
        isinstance(it, Table) and isinstance(it.value._previous_item(), Whitespace)
    ) or (isinstance(it, AoT) and len(it) > 0 and isinstance(it[-1], Whitespace))

ends_with_whitespace only check last and current without sub-tree.
Should subdata be checked ?

Activity

  1. dimbleby commented on Jun 6, 2026

    @dimbleby
    Contributor

    Does not reproduce today

  2. kdeldycke commented on Jun 10, 2026

    @kdeldycke

    Does not reproduce today

    It does, even with tomlkit 0.15.0.

    Proof:

    #!/usr/bin/env -S uv run --script
    # /// script
    # requires-python = ">=3.10"
    # dependencies = ["tomlkit==0.15.0"]
    # ///
    """Reproduce tomlkit#352 against tomlkit 0.15.0."""
    from __future__ import annotations
    
    import tomlkit
    from tomlkit.container import Container
    
    SOURCE = """\
    [env.pro1.rst]
    name = "x7"
    
    [env2]
    name = 2
    
    [env3]
    name = 3
    """
    
    
    def merge_dicts(a, b):
        """Walk ``b`` into ``a``, reassigning nested tables back onto their parent."""
        for k, v in b.items():
            if k in a and isinstance(a[k], (dict, Container)):
                a[k] = merge_dicts(a[k], v)
        return a
    
    
    def main() -> None:
        print(f"tomlkit {tomlkit.__version__}")
    
        doc = tomlkit.parse(SOURCE)
        merge_dicts(doc, {"env": {"pro1": {"rst": {"name": "x7"}}}})
        output = tomlkit.dumps(doc)
    
        print("--- input  ---")
        print(SOURCE, end="")
        print("--- output ---")
        print(output, end="")
        print("--------------")
    
        if output == SOURCE:
            print("OK: round-trip preserved")
            return
    
        extra = output.count("\n\n\n") - SOURCE.count("\n\n\n")
        print(f"BUG: round-trip diverged ({extra} extra blank line(s) inserted)")
        raise SystemExit(1)
    
    
    if __name__ == "__main__":
        main()

    Which produces:

    $ uv run ./issue_352-test.py
    tomlkit 0.15.0
    --- input  ---
    [env.pro1.rst]
    name = "x7"
    
    [env2]
    name = 2
    
    [env3]
    name = 3
    --- output ---
    [env.pro1.rst]
    name = "x7"
    
    
    [env2]
    name = 2
    
    [env3]
    name = 3
    --------------
    BUG: round-trip diverged (1 extra blank line(s) inserted)
    
  3. dimbleby commented on Jun 10, 2026

    @dimbleby
    Contributor

    oh I see - the original report provided a repro that did not actually do anything! So indeed nothing changed when I "executed" it...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions