python yaml update preserving order and comments

pyyaml cannot keep comments, but ruamel does.

Try this:

doc = ruamel.yaml.load(yaml, Loader=ruamel.yaml.RoundTripLoader)
doc['ParentTest']['test']['new_key'] = 'new value'
print ruamel.yaml.dump(doc, Dumper=ruamel.yaml.RoundTripDumper)

The order of keys will also be preserved.

Edit: Look at Anthon's answer from 2020: https://stackoverflow.com/a/59659659/93745


Addtion,if you want keep quote,you can try this:

import ruamel.yaml
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True

Although @tinita's answer works, it uses the old ruamel.yaml API and that gives you less control over the loading/dumping. Even so, you cannot preserve the inconsistent indentation of your mappings: the key ParentTest is indented four positions, the key test a further three and the key JOb1 only two positions. You can "only" set the same indentation for all mappings (i.e their keys), and separate from that the indentation of all sequences (i.e. their elements) and if there is enough space, you can offset the sequence indicator (-) within the sequence element indent.

In the default, round-trip mode, ruamel.yaml preserves key order, and additionally you can preserve quotes, folded and literal scalars.

With a slightly extended YAML input as example:

import sys
import ruamel.yaml

yaml_str = """\
#This Key is used for identifying Parent tests
    ParentTest:
       test:
         JOb1:
           - my
           - job
        #   ^ four indent positions for the sequence elements
        # ^   two position offset for the sequence indicator '-'
         name: 'testjob'  # quotes added to show working of .preserve_quotes = True
         arrive: yes
"""

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True
params = yaml.load(yaml_str)
params['ParentTest']['test']['new_key'] = 'new value'
params['ParentTest']['test'].yaml_add_eol_comment('some comment', key='new_key', column=40) # column is optional
yaml.dump(params, sys.stdout)

which gives:

#This Key is used for identifying Parent tests
ParentTest:
    test:
        JOb1:
          - my
          - job
        #   ^ four indent positions for the sequence elements
        # ^   two position offset for the sequence indicator '-'
        name: 'testjob'   # quotes added to show working of .preserve_quotes = True
        arrive: yes
        new_key: new value              # some comment