'Preserving quotes in ruamel.yaml

I'm using ruamel.yaml for modifying a YAML file. My requirement is to add a value for an existing key, preserving everything else including the order. I got it to work, but looks like quotation marks of other keys/values get modified too in the process.

  1. For some cases, double quotes get converted to single quotes. E.g.

    Before

    node_js:
      - "0.10"
    

    After

    node_js:
      - '0.10'
    
  2. In some other cases, quotes get dropped altogether. E.g.:

    Before

    before_script:
      - "cp test/config-x.js src/config.js"
    

    After

    before_script:
     - cp test/config-x.js src/config.js
    

Both of these cases appear in the same file. How can I stop this from happening and preserve the quotes as it is in the original?

I use load_yaml_guess_indent() for loading and round_trip_dump() for writing it back.



Solution 1:[1]

By default ruamel.yaml "normalizes" things like indentation and removes any superfluous quotes. It also defaults to the single quotes on output, when those are necessary as those indicate simpler strings (i.e. only single quotes have special meaning and these are a better/simpler option to distinguish strings that could be interpreted as numbers than double quotes are).

What you probably missed is that you explicitly have to tell the round_trip_loader() to preserve quotes, using the preserve_quotes=True argument:

import sys
import ruamel.yaml

yaml_str_1 = """\
node_js:
  - "0.10"
"""

yaml_str_2 = """\
before_script:
  - "cp test/config-x.js src/config.js"
"""

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = Truej
data = ruamel.yaml.load(yaml_str_1)
ruamel.yaml.dump(data, sys.stdout)
print('=====')
data = ruamel.yaml.load(yaml_str_2)
ruamel.yaml.dump(data, sys.stdout)

gives:

node_js:
- "0.10"
=====
before_script:
- "cp test/config-x.js src/config.js"

With that option all strings are loaded in special subclasses of strings that are then output as they were loaded. These classes need to be used if you replace such a loaded value, as just assigning a new value will not preserve the type. Adding:

data['before_script'][0] = type(data['before_script'][0])('ln -s xxx /usr/local/bin')
ruamel.yaml.round_trip_dump(data, sys.stdout)

gives:

before_script:
- "ln -s xxx /usr/local/bin"

(that type happens to be ruamel.yaml.scalarstring.DoubleQuotedScalarString())

Solution 2:[2]

yaml.preserve_quotes = True works in the current version of ruamel.yaml.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Christian Berendt