PyYAML dump format

Viewed 88732

I know there are a few questions about this on StackOverflow, but I couldn't find what I was looking for.

I'm using pyyaml to read (.load()) a .yml file, modify or add a key, and then write it (.dump()) again. The problem is that I want to keep the file format post-dump, but it changes.

For example, I edit the key en.test.index.few to say "Bye" instead of "Hello".

Python:

with open(path, "r", encoding = "utf-8") as yaml_file:
    self.dict = yaml.load(yaml_file)

Then, after changing the key:

with open(path, "w", encoding = "utf-8") as yaml_file:
    dump = pyyaml.dump(self.dict, default_flow_style = False, allow_unicode = True, encoding = None)
    yaml_file.write( dump )

Yaml:

Before:

en:
  test:
    new: "Bye"
    index:
      few: "Hello"
  anothertest: "Something"

After:

en:
  anothertest: Something
  test:
    index:
      few: Hello
    new: Bye

Is there a way to keep the same format? For example the qoutes and order. Am I using the wrong tool for this?

I know maybe the original file it's not entirely correct, but I have no control over it (it's a Ruby-on-Rails i18n file).

Thank you very much.

3 Answers

In my case, I want " if value contains a { or a }, otherwise nothing. For example:

 en:
   key1: value is 1
   key2: 'value is {1}'

To perform that, copy function represent_str() from file representer.py in module PyYaml and use another style if string contains { or a }:

def represent_str(self, data):
    tag = None
    style = None
    # Add these two lines:
    if '{' in data or '}' in data:
        style = '"'
    try:
        data = unicode(data, 'ascii')
        tag = u'tag:yaml.org,2002:str'
    except UnicodeDecodeError:
        try:
            data = unicode(data, 'utf-8')
            tag = u'tag:yaml.org,2002:str'
        except UnicodeDecodeError:
            data = data.encode('base64')
            tag = u'tag:yaml.org,2002:binary'
            style = '|'
    return self.represent_scalar(tag, data, style=style)

To use it in your code:

import yaml

def represent_str(self, data):
  ...

yaml.add_representer(str, represent_str)

In this case, no diffences between keys and values and that's enough for me. If you want a different style for keys and values, perform the same thing with function represent_mapping

Related