keheliya
keheliya

Reputation: 2553

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.

Upvotes: 16

Views: 15996

Answers (2)

Anthon
Anthon

Reputation: 76599

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 = True
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())

Upvotes: 7

Christian Berendt
Christian Berendt

Reputation: 1935

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

Upvotes: 21

Related Questions