toml icon indicating copy to clipboard operation
toml copied to clipboard

Error message is confusing to users unfamiliar with toml

Open dgrunwald opened this issue 5 years ago • 3 comments

A user using some_tool might need to change its configuration some day. They write:

[some_tool]
show = all

which results in the error message:

$ python3 -c "import toml; toml.loads('show = all')"
Traceback (most recent call last):
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 510, in loads
    ret = decoder.load_line(line, currentlevel, multikey,
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 777, in load_line
    value, vtype = self.load_value(pair[1], strictly_valid)
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 913, in load_value
    v = int(v, 0)
ValueError: invalid literal for int() with base 0: 'all'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 513, in loads
    raise TomlDecodeError(str(err), original, pos)
toml.decoder.TomlDecodeError: invalid literal for int() with base 0: 'all' (line 1 column 1 char 0)

Users dealing with some_tool aren't experts in configuration languages; they don't know that JSON+TOML need quotes whereas INI+YAML don't. It would be helpful if the error message could mention that string values need quotes.

dgrunwald avatar Aug 06 '20 12:08 dgrunwald

Another one:

$ python3 -c "import toml; toml.loads('quality = best')"
Traceback (most recent call last):
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 510, in loads
    ret = decoder.load_line(line, currentlevel, multikey,
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 777, in load_line
    value, vtype = self.load_value(pair[1], strictly_valid)
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 905, in load_value
    raise ValueError("This float doesn't have a leading "
ValueError: This float doesn't have a leading digit

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python38\lib\site-packages\toml\decoder.py", line 513, in loads
    raise TomlDecodeError(str(err), original, pos)
toml.decoder.TomlDecodeError: This float doesn't have a leading digit (line 1 column 1 char 0)

The first thought here was "this is a bug in some_tool" until a colleague spotted the missing quotes.

dgrunwald avatar Aug 06 '20 12:08 dgrunwald

Hey, maybe it's not an ideal solution, but you should do the parsing within a try / except block, so you could catch the data contained in the exception, which you can see here: https://github.com/uiri/toml/blob/9be64582fff86b9c5bd94ce52a5fedcb3d4fac01/toml/decoder.py#L50-L62

It would be great to document this, by the way!

So, you can do something like this.

try:
    parsed_toml = toml.loads(toml_string)
except toml.decoder.TomlDecodeError as e:
    print("Error when parsing the TOML file!")
    print(f"The error is on line {e.lineno} at column {e.colno}.")
    exit(1)
    # You can also do a 'raise' to raise the exception after the prints, for example.

Hope it helps!

rezemika avatar Sep 02 '20 19:09 rezemika

Another one (tested in release 0.10.2 and in current master):

In [1]: import toml

In [2]: toml.__version__
Out[2]: '0.10.2'

In [3]: dct = {'foo': 'bar', 'baz': ['qux', {'quux': 10}]}

In [4]: toml.dumps(dct)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-90f518bedf96> in <module>
----> 1 toml.dumps(dct)

~/mambaforge/envs/dev/lib/python3.7/site-packages/toml/encoder.py in dumps(o, encoder)
     58     if encoder is None:
     59         encoder = TomlEncoder(o.__class__)
---> 60     addtoretval, sections = encoder.dump_sections(o, "")
     61     retval += addtoretval
     62     outer_objs = [id(o)]

~/mambaforge/envs/dev/lib/python3.7/site-packages/toml/encoder.py in dump_sections(self, o, sup)
    201                         arraytabstr = "\n"
    202                         arraystr += "[[" + sup + qsection + "]]\n"
--> 203                         s, d = self.dump_sections(a, sup + qsection)
    204                         if s:
    205                             if s[0] == "[":

~/mambaforge/envs/dev/lib/python3.7/site-packages/toml/encoder.py in dump_sections(self, o, sup)
    191             if not re.match(r'^[A-Za-z0-9_-]+$', section):
    192                 qsection = _dump_str(section)
--> 193             if not isinstance(o[section], dict):
    194                 arrayoftables = False
    195                 if isinstance(o[section], list):

TypeError: string indices must be integers

I now understand my error (mixing types in an array) but my request is: Could you catch this and report a more user-friendly error? "TypeError: string indices must be integers" doesn't help me much. Something like TomlError: arrays can not include mixed types would be a huge step forward here. Lucky for me, I caught this in a minimal test suite, so it was easy to form a hypothesis, isolate the error, and confirm the problem by searching the web.

dwhswenson avatar Sep 06 '21 07:09 dwhswenson