toml-cli icon indicating copy to clipboard operation
toml-cli copied to clipboard

toml set added a duplicated table when parent table is defined after child table

Open cyliu0 opened this issue 9 months ago • 2 comments

$ cat test.toml
[root.d1]
f1="f1"
[root]
f2="f2"

# It seems like the toml-cli can't deal with the tables which parent table is defined after child table?
$ toml set --toml-path test.toml root.f3 "f3"
$ cat test.toml
[root]
f3 = "f3"
[root.d1]
f1="f1"
[root]
f2="f2"

$ toml set --toml-path test.toml root.f3 "f3"
╭──────────────────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ /opt/homebrew/lib/python3.10/site-packages/tomlkit/parser.py:161 in parse                                                                                                                                                                  │
│                                                                                                                                                                                                                                            │
│    158 │   │   │   │   value = self._parse_aot(value, key)                                      ╭─────────────────────── locals ────────────────────────╮                                                                                  │
│    159 │   │   │                                                                                │  body = {'root': {'f3': 'f3', 'd1': {'f1': 'f1'}}}    │                                                                                  │
│    160 │   │   │   try:                                                                         │   key = <Key root>                                    │                                                                                  │
│ ❱  161 │   │   │   │   body.append(key, value)                                                  │  self = <tomlkit.parser.Parser object at 0x10209d6c0> │                                                                                  │
│    162 │   │   │   except Exception as e:                                                       │ value = {'f2': 'f2'}                                  │                                                                                  │
│    163 │   │   │   │   raise self.parse_error(ParseError, str(e)) from e                        ╰───────────────────────────────────────────────────────╯                                                                                  │
│    164                                                                                                                                                                                                                                     │
│                                                                                                                                                                                                                                            │
│ /opt/homebrew/lib/python3.10/site-packages/tomlkit/container.py:265 in append                                                                                                                                                              │
│                                                                                                                                                                                                                                            │
│   262 │   │   │   │   │   elif current_body_element[0].is_dotted():                            ╭─────────────────────────────── locals ────────────────────────────────╮                                                                   │
│   263 │   │   │   │   │   │   raise TOMLKitError("Redefinition of an existing table")          │              current = {'f3': 'f3', 'd1': {'f1': 'f1'}}               │                                                                   │
│   264 │   │   │   │   elif not item.is_super_table():                                          │ current_body_element = (<Key root>, {'f3': 'f3', 'd1': {'f1': 'f1'}}) │                                                                   │
│ ❱ 265 │   │   │   │   │   raise KeyAlreadyPresent(key)                                         │          current_idx = 0                                              │                                                                   │
│   266 │   │   │   elif isinstance(item, AoT):                                                  │                 item = {'f2': 'f2'}                                   │                                                                   │
│   267 │   │   │   │   if not isinstance(current, AoT):                                         │                  key = <Key root>                                     │                                                                   │
│   268 │   │   │   │   │   # Tried to define an AoT after a table with the same name.           │                 prev = {'f3': 'f3', 'd1': {'f1': 'f1'}}               │                                                                   │
│                                                                                                │              prev_ws = False                                          │                                                                   │
│                                                                                                │                 self = {'root': {'f3': 'f3', 'd1': {'f1': 'f1'}}}     │                                                                   │
│                                                                                                │             validate = True                                           │                                                                   │
│                                                                                                ╰───────────────────────────────────────────────────────────────────────╯                                                                   │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
KeyAlreadyPresent: Key "root" already exists.

The above exception was the direct cause of the following exception:

╭──────────────────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ /opt/homebrew/lib/python3.10/site-packages/toml_cli/__init__.py:73 in set_                                                                                                                                                                 │
│                                                                                                                                                                                                                                            │
│    70 │   ),                                                                                   ╭────────────── locals ──────────────╮                                                                                                      │
│    71 ):                                                                                       │       key = 'root.f3'              │                                                                                                      │
│    72 │   """Set a value to a toml file"""                                                     │  to_array = False                  │                                                                                                      │
│ ❱  73 │   toml_part = toml_file = tomlkit.parse(toml_path.read_text())                         │   to_bool = False                  │                                                                                                      │
│    74 │                                                                                        │  to_float = False                  │                                                                                                      │
│    75 │   for key_part in key.split(".")[:-1]:                                                 │    to_int = False                  │                                                                                                      │
│    76 │   │   try:                                                                             │ toml_path = PosixPath('test.toml') │                                                                                                      │
│                                                                                                │     value = 'f3'                   │                                                                                                      │
│                                                                                                ╰────────────────────────────────────╯                                                                                                      │
│                                                                                                                                                                                                                                            │
│ /opt/homebrew/lib/python3.10/site-packages/tomlkit/api.py:91 in parse                                                                                                                                                                      │
│                                                                                                                                                                                                                                            │
│    88 │   """                                                                                  ╭────────────────────────────── locals ───────────────────────────────╮                                                                     │
│    89 │   Parses a string or bytes into a TOMLDocument.                                        │ string = '[root]\nf3 = "f3"\n[root.d1]\nf1="f1"\n[root]\nf2="f2"\n' │                                                                     │
│    90 │   """                                                                                  ╰─────────────────────────────────────────────────────────────────────╯                                                                     │
│ ❱  91 │   return Parser(string).parse()                                                                                                                                                                                                    │
│    92                                                                                                                                                                                                                                      │
│    93                                                                                                                                                                                                                                      │
│    94 def document() -> TOMLDocument:                                                                                                                                                                                                      │
│                                                                                                                                                                                                                                            │
│ /opt/homebrew/lib/python3.10/site-packages/tomlkit/parser.py:163 in parse                                                                                                                                                                  │
│                                                                                                                                                                                                                                            │
│    160 │   │   │   try:                                                                         ╭─────────────────────── locals ────────────────────────╮                                                                                  │
│    161 │   │   │   │   body.append(key, value)                                                  │  body = {'root': {'f3': 'f3', 'd1': {'f1': 'f1'}}}    │                                                                                  │
│    162 │   │   │   except Exception as e:                                                       │   key = <Key root>                                    │                                                                                  │
│ ❱  163 │   │   │   │   raise self.parse_error(ParseError, str(e)) from e                        │  self = <tomlkit.parser.Parser object at 0x10209d6c0> │                                                                                  │
│    164 │   │                                                                                    │ value = {'f2': 'f2'}                                  │                                                                                  │
│    165 │   │   body.parsing(False)                                                              ╰───────────────────────────────────────────────────────╯                                                                                  │
│    166                                                                                                                                                                                                                                     │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ParseError: Key "root" already exists. at line 6 col 0

cyliu0 avatar Apr 02 '25 08:04 cyliu0

Thanks for the isssue. Too bad, the issue is caused by the underlying toml document library. So it is not an easy fix. I will check if I can make a PR for that library or use another one.

mrijken avatar Apr 02 '25 17:04 mrijken

It's OK. I also found it should be a tomlkit bug.

cyliu0 avatar Apr 03 '25 01:04 cyliu0