Search code examples
pythonyamlruamel.yaml

Mix flow and block style in YAML dump


I am using Python 3.8.10 and ruamel 0.17.31. I have this python dict

d = {'a': {'b': {'c': {'x': 1, 'y': 1}, 'd': [1, 2, 3], 'e': {'f': 1, 'g': 1} }}}

Using ruamel.yaml, I want it to be printed like:

a:
  b:
    c:
      x: 1
      y: 1
    d: [1, 2, 3]
    e:
      f: 1
      g: 1

I think I am mixing the flow and block styles. By using the default_flow_style I can either of the one output

a:
  b:
    c:
      x: 1
      y: 1
    d:
    - 1
    - 2
    - 3
    e:
      f: 1
      g: 1

or

a:
  b:
    c: {x: 1, y: 1}
    d: [1, 2, 3]
    e: {f: 1, g: 1}

Do I need to write a custom representer?


Solution

  • You could write a custom representer that only emits sequences using flow-style when that sequence doesn't contain any collections itself (i.e. only contains scalars). That is non-trivial, and probably also not necessary.

    As indicated in other answers, even if you don't know what to do, it is good to check if ruamel.yaml can round-trip what you want to get:

    import sys
    import ruamel.yaml
    
    yaml_str = """\
    a:
      b:
        c:
          x: 1
          y: 1
        d: [1, 2, 3]
        e:
          f: 1
          g: 1
    """
        
    yaml = ruamel.yaml.YAML()
    data = yaml.load(yaml_str)
    yaml.dump(data, sys.stdout)
    

    which gives:

    a:
      b:
        c:
          x: 1
          y: 1
        d: [1, 2, 3]
        e:
          f: 1
          g: 1
    

    So it can round-trip what you want, After which you can inspect how your special item is constructed during loading:

    flow_list = data['a']['b']['d']
    print(type(flow_list), flow_list)
    

    which then gives:

    <class 'ruamel.yaml.comments.CommentedSeq'> [1, 2, 3]
    

    So you need to construct a CommentedSeq and searching for that and ruamel.yaml and flow-style on StackOverflow should get you a limited list of answers (e.g. this one )

    To give a complete example to construct something from scratch and dump it:

    import sys
    import ruamel.yaml
    
    def FSlist(l):  # convert list into flow-style (default is block style)
        from ruamel.yaml.comments import CommentedSeq
        cs = CommentedSeq(l)
        cs.fa.set_flow_style()
        return cs
    
    yaml = ruamel.yaml.YAML()
    data = dict(a=dict(b=dict(c=dict(x=1, y=1), d=FSlist([1, 2, 3]), e=dict(f=1, g=1))))
    yaml.dump(data, sys.stdout)
    

    resulting in something close to what you wanted:

    a:
      b:
        c:
          x: 1
          y: 1
        d: [1, 2, 3]
        e:
          f: 1
          g: 1