Common mistakes

Two values for one key

When load() or loads() complains of errors it is important to look both at the line fingered by the error message and the one above it. The line that is the target of the error message might by an otherwise valid NestedText line if it were not for the line above it. For example, consider the following example:

Example:

>>> import nestedtext as nt

>>> content = """
... treasurer:
...     name: Fumiko Purvis
...     address: Home
...         > 3636 Buffalo Ave
...         > Topeka, Kansas 20692
... """

>>> try:
...     data = nt.loads(content)
... except nt.NestedTextError as e:
...     print(e.get_message())
...     print(e.get_codicil()[0])
invalid indentation.
An indent may only follow a dictionary or list item that does not
already have a value.
   4 ❬    address: Home❭
   5 ❬        > 3636 Buffalo Ave❭

Notice that the complaint is about line 5, but problem stems from line 4 where Home gave a value to address. With a value specified for address, any further indentation on line 5 indicates a second value is being specified for address, which is illegal.

A more subtle version of this same error follows:

Example:

>>> content = """
... treasurer:
...     name: Fumiko Purvis
...     address:␣␣
...         > 3636 Buffalo Ave
...         > Topeka, Kansas 20692
... """

>>> try:
...     data = nt.loads(content.replace('␣␣', '  '))
... except nt.NestedTextError as e:
...     print(e.get_message())
...     print(e.get_codicil()[0])
invalid indentation.
An indent may only follow a dictionary or list item that does not
already have a value, which in this case consists only of whitespace.
   4 ❬    address:  ❭
   5 ❬        > 3636 Buffalo Ave❭

Notice the ␣␣ that follows address in content. These are replaced by 2 spaces before content is processed by loads. Thus, in this case there is an extra space at the end of line 4. Anything beyond the: :␣ is considered the value for address, and in this case that is the single extra space specified at the end of the line. This extra space is taken to be the value of address, making the multiline string in lines 5 and 6 a value too many.

This mistake is easier to see in advance if you configure your editor to show trailing whitespace. To do so in Vim, add:

set listchars=trail:␣

to your ~/.vimrc file.

Lists or strings at the top level

Most NestedText files start with key-value pairs at the top-level and we noticed that many developers would simply assume this in their code, which would result in unexpected crashes when their programs read legal NestedText files that had either a list or a string at the top level. To avoid this, the load() and loads() functions are configured to expect a dictionary at the top level by default, which results in an error being reported if a dictionary key is not the first token found:

>>> import nestedtext as nt

>>> content = """
... - a
... - b
... """

>>> try:
...     print(nt.loads(content))
... except nt.NestedTextError as e:
...     e.report()
error: 2: content must start with key or brace ({).
       2 ❬- a❭

This restriction is easily removed using top:

>>> try:
...     print(nt.loads(content, top=list))
... except nt.NestedTextError as e:
...     e.report()
['a', 'b']

The top argument can take any of the values shown in the table below. The default value is dict. The value given for top also determines the value returned by load() and loads() if the NestedText document is empty.

top

value returned for empty document

“dict”, dict

{}

“list”, list

[]

“str”, str

""

“any”, any

None