How to properly set up YAML flow style dumping using round-trip with ruamel.yaml?

2k Views Asked by At

I am working with the ruamel.yaml package and I can't seem to get it to output in a nicely formatted flow style. I'd like to keep elements on the same level separated by trailing commas and newlines. I also would like to preserve every comment, and it seems that some disappear after converting to flow style. Here is an example:

Original

background_opacity: 0.9 # comment
cursor: {style: Beam}

# comment
font:
    normal: {family: Fira Code, style: Retina} # comment
    size: 12.0 # comment

Intended

{
    background_opacity: 0.9, # comment
    cursor: {style: Beam},
    
    # comment
    font: {
        normal: {family: Fira Code, style: Retina}, # comment
        size: 12.0 # comment
    }
}

Actual

{background_opacity: 0.9 # comment
, cursor: {style: Beam}, font: {normal: {family: Fira Code, style: Retina} # comment
, size: 12.0   # comment
}}

My code is attached below. I am pretty new to YAML and ruamel.yaml so I apologize for any simple mistakes.

from ruamel.yaml import YAML

def round_trip(sout, sin, idt):
    yaml = YAML()
    assert idt >= 2
    yaml.indent(mapping=idt, sequence=idt, offset=idt-2)
    yaml.preserve_quotes = True

    data = yaml.load(sin)
    if data is not None:
        data.fa.set_flow_style() # needs fixing: commas are not trailing
        yaml.dump(data, sout)
    else:
        print("the file is empty") # needs fixing: should dump original file
1

There are 1 best solutions below

6
On BEST ANSWER

You don't seem to be doing anything wrong, but ruamel.yaml doesn't support making that kind of output. It just tries to cram as much of a flow-style allows on a line, and that you get newlines at all is because outputting the comments (which are associated with the mapping keys before them, forces such a line-break.

If your input would not have any comments, then you end up with one or two lines depending on the output width that you set.

You might get a slightly better result if you on loading append a dummy comment to every line, and remove that after dumping, but that will still not get you opening braces on a line of their own.

Currently you are only setting the root level style attribute, that "works" because you have no nested block-style collections. You should do that recursively with something like:

def set_style(d, flow):
    if isinstance(d, dict):
        if flow:
            d.fa.set_flow_style()
        else:
            d.fa.set_block_style()
        for k in d:
            set_style(d[k], flow)
    elif isinstance(d, list):
        if flow:
            d.fa.set_flow_style()
        else:
            d.fa.set_block_style()
        for item in d:
             set_style(item, flow)


data = yaml.load(sin)
set_style(data, flow=True)