[Python] tomlkit dump behaving different with same data

Discussão em 'Python' iniciado por Stack, Maio 8, 2025.

  1. Stack

    Stack Membro Participativo

    I have a small config which I define via dataclasses and then read from a toml to this datastructure. If the toml file does not exists I create one with default values. If in an update some new config parameters where added I would like to take the toml from the user location, take the existing entries and then add the new one an write the file again. Everything is working fine, accept for the adding the entries, here there there are some empty lines added in the file and i dont know why. I already checked - the dict input to the tomlkit.dump command is exactly the same - still the output differs. Has anyone an idea where this could come from?

    This is my Dataclass (subclasses are not shown and should not matter):

    @dataclass
    class Config:
    general: General = field(default_factory=General)
    siemens: Siemens = field(default_factory=Siemens)
    def dict(self):
    return {k: v.dict() for k, v in self.__dict__.items()}

    @classmethod
    def load(cls, config_json):
    return Config(general=General(**config_json['general']), siemens=Siemens(**config_json['siemens']))


    this function adds missing keys (from the class) to the read toml file:

    def put_dict_params_into_toml_doc(default: dict, params: TOMLDocument) -> bool:
    params_missing = False
    for key, value in default.items():
    if isinstance(value, dict):
    try:
    child_params = params[key]
    if put_dict_params_into_toml_doc(value, child_params):
    params_missing = True
    except KeyError:
    print(f'using default "{value}" for "{key}" (not found in config params {params})')
    params_missing = True
    params[key] = value
    else:
    if key not in params:
    print(f'using default "{value}" for "{key}" (not found in config params {params})')
    params_missing = True
    params[key] = value
    return params_missing


    this function removes params from the toml file which are not in the class (if new version doesnt need parameter anymore):

    def remove_nonexisting_params(default: dict, params: any) -> any:
    result = params.copy()
    for key, value in params.items():
    if isinstance(value, dict):
    try:
    child_params = default[key]
    result[key] = remove_nonexisting_params(child_params, value)
    except KeyError:
    result.pop(key)
    else:
    if key not in default:
    result.pop(key)
    return result


    Here the toml file get read - this part is working perfectly (when file does not exist it is written with default values):

    def read_config(config_path:str) -> Config:
    default_params = Config()
    if os.path.exists(config_path):
    with open(config_path, mode="rb") as fp:
    config_params = tomlkit.load(fp)
    params_missing = put_dict_params_into_toml_doc(default_params.dict(), config_params)
    config_params = remove_nonexisting_params(default_params.dict(), config_params)
    if params_missing:
    write_config(config_path, Config.load(config_params))
    else:
    config_params = default_params.dict()
    with open(config_path, mode="w") as fp:
    tomlkit.dump(config_params, fp)
    return Config.load(config_params)


    Here the file should be written, when I use Config().dict() as config_params erverything is fine, only if in the missing_params path it adds some empty lines...

    def write_config(config_path:str, config_params:Config):
    with open(config_path, mode="w") as fp:
    tomlkit.dump(config_params.dict(), fp)


    Output when running when file does not exist:

    [general]
    test_ip_address = "x.x.x.x"
    test_eth_port = "eth3"
    duagon_ip_address = "x.x.x.x"
    duagon_eth_port = "eth0"
    logging_on = false
    xml_outputfile = "TRDP.xml"

    [siemens]
    support_multiple_devices = true
    stdv2_udev = [1]
    smi_send = [[123], [123]]
    smi_receive = [[123, 123]]


    Output when one line is removed for test:

    [general]
    test_ip_address = "x.x.x.x"

    test_eth_port = "eth3"

    duagon_ip_address = "x.x.x.x"

    duagon_eth_port = "eth0"

    logging_on = false
    xml_outputfile = "TRDP.xml"

    [siemens]
    support_multiple_devices = true
    stdv2_udev = [1]

    smi_send = [[123], [123]]

    smi_receive = [[123, 123]]

    Continue reading...

Compartilhe esta Página