sf8193
sf8193

Reputation: 635

tomli-w, adding arrays from a python script

I have a toml file like this

[[fruits]]
fruit_property =x

[[fruits]]
fruit_property =x

[[fruits]]
fruit_property =x

And I want to encode this from a python script. So far in python i have done

fruits= [
 {'fruit_property':x},{'fruit_property':y},  {'fruit_property':z}, 
]

toml_string = tomli_w.dumps(fruits)

and then writing the string to a file. However, this doesn't convert the array of dicts, and instead just keeps them the same way my code has them. I've looked and can't find any documentation for this, has anyone run into similar issues?

However, this does not convert

Upvotes: 1

Views: 227

Answers (2)

Wizard.Ritvik
Wizard.Ritvik

Reputation: 11680

I would also suggest dataclass-wizard, which provides recent TOML support via the TOMLWizard class. This is a modern approach that "just works" for Python 3.9+ and uses tomli-w for serializing TOML data.

However, I do agree with @Timeless that it appears to be a bug in how tomli-w works (even after adding the "fruits" key to group it under a header).

Example

To get started, install the library (which relies on minimal dependencies) with TOML support enabled:

pip install dataclass-wizard[toml]

Usage:

from dataclasses import dataclass
from dataclass_wizard import TOMLWizard


@dataclass
class Fruit(TOMLWizard):
    fruit_property: str


fruits = Fruit.from_toml("""
[[fruits]]
fruit_property = 'x'

[[fruits]]
fruit_property = 'y'

[[fruits]]
fruit_property = 'z'
""", header='fruits')


print(fruits)
print()

toml_string = Fruit.list_to_toml(fruits, header='fruits')
print(toml_string)

Output:

[Fruit(fruit_property='x'), Fruit(fruit_property='y'), Fruit(fruit_property='z')]

fruits = [
    { fruit_property = "x" },
    { fruit_property = "y" },
    { fruit_property = "z" },
]

As observed above, this does appear to be a bug in tomli-w. It seems that the nested dict elements within list are appearing as an inline table when serializing the data to TOML, which is odd.

Alternate Example

As an alternative to passing header="fruits" everywhere, you could also structure this with an outer (container) class:

from dataclasses import dataclass
from dataclass_wizard import TOMLWizard


@dataclass
class BagOfFruits(TOMLWizard):
    fruits: list['Fruit']


@dataclass
class Fruit:
    fruit_property: str


fruits = BagOfFruits.from_toml("""
[[fruits]]
fruit_property = 'x'

[[fruits]]
fruit_property = 'y'

[[fruits]]
fruit_property = 'z'
""")


print(fruits)
print()

toml_string = BagOfFruits.to_toml(fruits)
print(toml_string)

Getting it right with tomlkit

If you would like to dumps your fruits with tomlkit (!pip install tomlkit):

# !pip install tomlkit
import tomlkit

from dataclasses import dataclass
from dataclass_wizard import TOMLWizard


@dataclass
class Fruit(TOMLWizard):
    fruit_property: str


fruits = Fruit.from_toml("""
[[fruits]]
fruit_property = 'x'

[[fruits]]
fruit_property = 'y'

[[fruits]]
fruit_property = 'z'
""", header='fruits')


print(fruits)
print()

toml_string = Fruit.list_to_toml(fruits, header='fruits', encoder=tomlkit.dumps)
print(toml_string)

Corrected Output:

[Fruit(fruit_property='x'), Fruit(fruit_property='y'), Fruit(fruit_property='z')]

[[fruits]]
fruit_property = "x"

[[fruits]]
fruit_property = "y"

[[fruits]]
fruit_property = "z"

Upvotes: 0

Timeless
Timeless

Reputation: 37857

Seems like a bug in tomli-w (even after adding an outer "fruits" key).

I suggest you to dumps your fruits object with tomlkit (!pip install tomlkit) :

import tomlkit

fruits = [
    {"fruit_property": "x"}, {"fruit_property": "y"}, {"fruit_property": "z"},
]

toml_string = tomlkit.dumps({"fruits": fruits})

Output :

print(toml_string)

[[fruits]]
fruit_property = "x"

[[fruits]]
fruit_property = "y"

[[fruits]]
fruit_property = "z"

Upvotes: 1

Related Questions