Prevent ruamel yaml.dump to ident comment block after aliases

Viewed 41

I've got newline offset when trying to load-dump yaml with comments and aliases using ruamel.yaml. How to prevent this?

import ruamel.yaml


yaml_conetent = \
"""
entities:
  leg0: &leg0
    claws:
      leg0claw0: {}
      leg0claw1: {}
  leg1: &leg1
    claws:
      leg1claw0: {}
      leg1claw1: {}
  leg2: &leg2
    claws:
      leg2claw0: {}
      leg2claw1: {}
  leg3: &leg3
    claws:
      leg3claw0: {}
      leg3claw1: {}
anchors:
  cat_with_4_legs: &cat_with_4_legs
    legs:
      leg0: *leg0
      leg1: *leg1
      leg2: *leg2
      leg3: *leg3
cats:
  athena: *cat_with_4_legs      # RED
  ares: *cat_with_4_legs      # WHITE
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_conetent)
yaml.dump(data, sys.stdout)

Which results in:

...
cats:
  athena: *cat_with_4_legs
                                # RED
  ares: *cat_with_4_legs
                              # WHITE

Expected output:

...
cats:
  athena: *cat_with_4_legs      # RED
  ares: *cat_with_4_legs      # WHITE
1 Answers

This is a bug in ruamel.yaml, and it is unclear so far what causes this.

I suggest you postprocess the output for now:

import sys
import ruamel.yaml

yaml_str = """\
entities:
  leg0: &leg0
    claws:
      leg0claw0: {}
      leg0claw1: {}
  leg1: &leg1
    claws:
      leg1claw0: {}
      leg1claw1: {}
  leg2: &leg2
    claws:
      leg2claw0: {}
      leg2claw1: {}
  leg3: &leg3
    claws:
      leg3claw0: {}
      leg3claw1: {}
anchors:
  cat_with_4_legs: &cat_with_4_legs
    legs:
      leg0: leg0
      leg1: leg1
      leg2: leg2
      leg3: leg3
cats:
  athena: *cat_with_4_legs      # RED
  ares: *cat_with_4_legs      # WHITE
"""

def fix_alias_comment(s):
    res = []
    alias_line = None
    for line in s.splitlines(True):
        if ': *' in line:
            alias_line = len(line) - 1
            res.append(line)
            continue
        if alias_line is not None and line.startswith(' ' * alias_line):
            res[-1] = res[-1][:-1] + line[alias_line:]
            continue
        res.append(line)
    return ''.join(res)
    
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout, transform=fix_alias_comment)

which gives:

entities:
  leg0:
    claws:
      leg0claw0: {}
      leg0claw1: {}
  leg1:
    claws:
      leg1claw0: {}
      leg1claw1: {}
  leg2:
    claws:
      leg2claw0: {}
      leg2claw1: {}
  leg3:
    claws:
      leg3claw0: {}
      leg3claw1: {}
anchors:
  cat_with_4_legs: &cat_with_4_legs
    legs:
      leg0: leg0
      leg1: leg1
      leg2: leg2
      leg3: leg3
cats:
  athena: *cat_with_4_legs      # RED
  ares: *cat_with_4_legs      # WHITE

Ugly, but it does the job

Related