About

ruamel.yaml is a YAML 1.2 loader/dumper package for Python. It is a derivative of Kirill Simonov’s PyYAML 3.11

ruamel.yaml supports YAML 1.2 and has round-trip loaders and dumpers that preserves, among others:

  • comments
  • block style and key ordering are kept, so you can diff the round-tripped source
  • flow style sequences ( ‘a: b, c, d’) (based on request and test by Anthony Sottile)
  • anchors names that are hand-crafted (i.e. not of the formidNNN)
  • merges in dictionaries are preserved

You can read more at http://yaml.readthedocs.io/en/latest/overview.html

Importing


In [1]:
import ruamel.yaml

In [2]:
ruamel.yaml


Out[2]:
<module 'ruamel.yaml' from '/usr/tmp/python3/lib/python3.4/site-packages/ruamel/yaml/__init__.py'>

In [3]:
ruamel


Out[3]:
<module 'ruamel'>

In [4]:
dir(ruamel)


Out[4]:
['__doc__',
 '__loader__',
 '__name__',
 '__package__',
 '__path__',
 '__spec__',
 'std',
 'yaml']

In [6]:
inp = """\
# example
name:
    # details
    family: Goda   # Very uncommon
    given: Satish  # One of the siblings (Comman name)
"""

In [7]:
print(inp)


# example
name:
    # details
    family: Goda   # Very uncommon
    given: Satish  # One of the siblings (Comman name)


In [8]:
help(ruamel.yaml.load)


Help on function load in module ruamel.yaml.main:

load(stream, Loader=None, version=None, preserve_quotes=None)
    Parse the first YAML document in a stream
    and produce the corresponding Python object.


In [9]:
code = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)

In [10]:
code


Out[10]:
CommentedMap([('name',
               CommentedMap([('family', 'Goda'), ('given', 'Satish')]))])

In [11]:
code['name']['given']


Out[11]:
'Satish'

In [12]:
code['name']['family']


Out[12]:
'Goda'

Anchors and References

API Study

Based on the example (abridged version)


In [13]:
import ruamel.yaml

inp = """\
- &CENTER {x: 1, y: 2}
- &LEFT {x: 0, y: 2}
- &BIG {r: 10}
- &SMALL {r: 1}
"""

In [14]:
code = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)

In [15]:
code


Out[15]:
[CommentedMap([('x', 1), ('y', 2)]),
 CommentedMap([('x', 0), ('y', 2)]),
 CommentedMap([('r', 10)]),
 CommentedMap([('r', 1)])]

In [16]:
type(code)


Out[16]:
ruamel.yaml.comments.CommentedSeq

In [17]:
dir(code)


Out[17]:
['__add__',
 '__class__',
 '__contains__',
 '__deepcopy__',
 '__delattr__',
 '__delitem__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__gt__',
 '__hash__',
 '__iadd__',
 '__imul__',
 '__init__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__module__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__reversed__',
 '__rmul__',
 '__setattr__',
 '__setitem__',
 '__sizeof__',
 '__slots__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 '_yaml_add_comment',
 '_yaml_add_eol_comment',
 '_yaml_comment',
 '_yaml_format',
 '_yaml_get_column',
 '_yaml_get_columnX',
 '_yaml_get_pre_comment',
 '_yaml_line_col',
 '_yaml_set_idx_line_col',
 '_yaml_set_kv_line_col',
 '_yaml_set_line_col',
 'anchor',
 'append',
 'ca',
 'clear',
 'copy',
 'copy_attributes',
 'count',
 'extend',
 'fa',
 'index',
 'insert',
 'lc',
 'pop',
 'remove',
 'reverse',
 'sort',
 'tag',
 'yaml_add_eol_comment',
 'yaml_anchor',
 'yaml_end_comment_extend',
 'yaml_key_comment_extend',
 'yaml_set_anchor',
 'yaml_set_comment_before_after_key',
 'yaml_set_start_comment',
 'yaml_set_tag',
 'yaml_value_comment_extend']

In [18]:
code.anchor


Out[18]:
<ruamel.yaml.comments.Anchor at 0x7fe7fc7cb518>

In [19]:
code.anchor.value

In [20]:
code.keys()


---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-20-9f05455810df> in <module>()
----> 1 code.keys()

AttributeError: 'CommentedSeq' object has no attribute 'keys'

In [21]:
for item in code:
    print(item)


CommentedMap([('x', 1), ('y', 2)])
CommentedMap([('x', 0), ('y', 2)])
CommentedMap([('r', 10)])
CommentedMap([('r', 1)])

In [22]:
for item in code:
    print(item.anchor.value, item.keys())


CENTER CommentedMapKeysView(CommentedMap([('x', 1), ('y', 2)]))
LEFT CommentedMapKeysView(CommentedMap([('x', 0), ('y', 2)]))
BIG CommentedMapKeysView(CommentedMap([('r', 10)]))
SMALL CommentedMapKeysView(CommentedMap([('r', 1)]))

Full example


In [23]:
import ruamel.yaml

inp = """\
- &CENTER {x: 1, y: 2}
- &LEFT {x: 0, y: 2}
- &BIG {r: 10}
- &SMALL {r: 1}

# All the following maps are equal:

# Explicit keys
- x: 1
  y: 2
  r: 10
  label: center/big

# Merge one map
- <<: *CENTER
  r: 10
  label: center/big

# Merge multiple maps
- <<: [*CENTER, *BIG]
  label: center/big
  
# Override
- <<: [*BIG, *LEFT, *SMALL]
  x: 1
  label: center/big
"""

In [24]:
data = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)

In [25]:
data


Out[25]:
[CommentedMap([('x', 1), ('y', 2)]),
 CommentedMap([('x', 0), ('y', 2)]),
 CommentedMap([('r', 10)]),
 CommentedMap([('r', 1)]),
 CommentedMap([('x', 1), ('y', 2), ('r', 10), ('label', 'center/big')]),
 CommentedMap([('r', 10), ('label', 'center/big'), ('x', 1), ('y', 2)]),
 CommentedMap([('label', 'center/big'), ('x', 1), ('y', 2), ('r', 10)]),
 CommentedMap([('x', 1), ('label', 'center/big'), ('r', 10), ('y', 2)])]

In [26]:
# Modifying the merge order of the aliases

inp = """\
- &CENTER {x: 1, y: 2}
- &LEFT {x: 0, y: 2}
- &BIG {r: 10}
- &SMALL {r: 1}

# All the following maps are equal:

# Explicit keys
- x: 1
  y: 2
  r: 10
  label: center/big

# Merge one map
- <<: *CENTER
  r: 10
  label: center/big

# Merge multiple maps
- <<: [*CENTER, *BIG]
  label: center/big
  
# Override
- <<: [*SMALL, *BIG, *LEFT]
  x: 1
  label: center/small
"""

In [27]:
data = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)

In [28]:
data


Out[28]:
[CommentedMap([('x', 1), ('y', 2)]),
 CommentedMap([('x', 0), ('y', 2)]),
 CommentedMap([('r', 10)]),
 CommentedMap([('r', 1)]),
 CommentedMap([('x', 1), ('y', 2), ('r', 10), ('label', 'center/big')]),
 CommentedMap([('r', 10), ('label', 'center/big'), ('x', 1), ('y', 2)]),
 CommentedMap([('label', 'center/big'), ('x', 1), ('y', 2), ('r', 10)]),
 CommentedMap([('x', 1), ('label', 'center/small'), ('r', 1), ('y', 2)])]

In [29]:
assert data[7]['y'] == 2

Inserting Keys and Comments


In [30]:
yaml_str = """\
first_name: Art
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...
"""

data = ruamel.yaml.round_trip_load(yaml_str)

In [31]:
data


Out[31]:
CommentedMap([('first_name', 'Art'),
              ('occupation', 'Architect'),
              ('about',
               'Art Vandelay is a fictional character that George invents...')])

In [32]:
data.insert(1, 'last name', 'Vandelay', comment='new key')

In [33]:
print(ruamel.yaml.round_trip_dump(data))


first_name: Art
last name: Vandelay    # new key
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...