Preserving quotes in ruamel.yaml
Asked Answered
I

2

16

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.

Inamorata answered 7/2, 2017 at 16:7 Comment(3)
I somehow overlooked that you are using load_yaml_guess_indent(), you can specify preserve_quotes=True for that function as well, that argument will be passed on to the round_trip_load() functionNorma
Thanks. I got that figured. It'll be nice to have a reference to all the options that are supported, like this.Inamorata
Sorry to be slow, but data, ind, bsi = load_yaml_guess_indent(open(file_name),preserve_quotes=True) gets me a TypeError: YAML.load() got an unexpected keyword argument 'preserve_quotes' error. am i missing something?Podium
N
7

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

Norma answered 7/2, 2017 at 18:23 Comment(0)
A
21

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

Apprehensible answered 1/8, 2018 at 10:9 Comment(0)
N
7

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

Norma answered 7/2, 2017 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.