Search code examples
pythonyamlruamel.yaml

Display a list from Python as flow style inside a block style yaml file (ruamel.yaml)


I am using ruamel.yaml to create a YAML file from a Python dictionary. Within the dictionary, there's a list as the value for the 'type' key. I've been looking all day now for examples to solve my problem, but can't find anything in the docs.

I've been trying to get a YAML file output like this:

 some_key:
  - id: 1059
    parameter: Paramter1
    unit: kg
    type: [A, B, C, 1, 2, 3]

That means the list after type is a flow-style element within the block style, which is the actual reason I switched to ruamel.yaml, because I read that it might be possible as opposed to PyYAML (Mixing block and flow formatting in YAML with Python). But in there I couldn't find what I am trying to do.

What I (unsurprisingly) get when I call

yaml.dump() 

on the dictionary is

some_key:
  - id: 1059
    parameter: Paramter1
    unit: kg
    type:
          - A 
          - B
          - C
          - '1'
          - '2'
          - '3'

Does anyone have a clue how this is solvable? A useful information might or might not be, that the list concerned could also be converted to different formats (e.g string), I get it from a csv-sheet.

UPDATE, here is a code example of what I've been trying:

A CSV-line looks like this:

"","",Parameter 1,Dropdown,kg,"","","A,B,C,1,2,3"

and in the conversion.py something like:

with open(csv_filename, "r") as file:
reader = csv.reader(file)
data = {"some_key": []}
for position, line in enumerate(reader):
        if line[3] == "Dropdown":
            select_options = []
            for item in line[7].split(","):
                select_options.append(item)
            select_options = [x.strip(" ") for x in select_options]
            type = f"{select_options}"
        dict = {
            "id": "tbd",
            "parameter": line[2].strip(" "),
            "unit": line[4].strip(" "),
            "type": type,
        }
        data["some_key"].append(dict)
doc = yaml.dump(data, file)

Solution

  • First of all, you need to define numbers as numbers, and not as strings, to get the output of those non-quoted ( 3 instead of '3' )

    Second you need to call yaml.indent() as the sequence indent of 3 positions with an offset for the sequence delimiter of 1, is non-standard.

    Then to fine-control a single list flow style you need to add that list as a CommentedSeq and call the set_flow_style() method on its fa attribute:

    import sys
    import ruamel.yaml
    
    
    def seq(*l):
      s = ruamel.yaml.comments.CommentedSeq(l)
      s.fa.set_flow_style()
      return s
    
    
    data = dict(some_key=[
        {
            'id': 1059,
            'parameter': 'Paramter1',
            'unit': 'kg',
            'type': seq('A', 'B', 'C', 1, 2, 3)
        },
    ])
    
    yaml = ruamel.yaml.YAML()
    yaml.indent(mapping=2, sequence=3, offset=1)
    yaml.dump(data, sys.stdout)
    

    which gives:

    some_key:
      - id: 1059
        parameter: Paramter1
        unit: kg
        type: [A, B, C, 1, 2, 3]
    

    In your example, you could have set yaml.default_flow_style = None before dumping and using a "normal" list. But that will affect all other "leaf-node" lists and dicts as well.