Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python use Pyyaml and keep format

Tags:

python

yaml

Here is a config file, I use PyYAML to change some value from it and then I write some config, but it will change my format, it confuses me.

 $ results.yaml 
 nas:
     mount_dir: '/nvr'
     mount_dirs: ['/mount/data0', '/mount/data1', '/mount/data2']

# yaml.py

import yaml.py

conf = open("results.conf", "r")
results = yaml.load(conf)
conf.close()

result['nas']['mount_dirs'][0]= "haha"

with open('/home/zonion/speedio/speedio.conf', 'w') as conf:
    yaml.dump(speedio, conf, default_flow_style=False)

conf.close()

but it change my format,what should I do?

# cat results.conf
nas:
  mount_dir: /nvr
  mount_dirs:
  - haha
  - /mount/data1
  - /mount/data2
like image 541
haroldT Avatar asked Oct 25 '16 08:10

haroldT


People also ask

Is PyYAML same as YAML?

YAML is a data serialization format designed for human readability and interaction with scripting languages. PyYAML is a YAML parser and emitter for the Python programming language.

How do I save as YAML in Python?

Open config.py and add the following lines of code just below the read_yaml method and above the main block of the file. In the write_yaml method, we open a file called toyaml. yml in write mode and use the YAML packages' dump method to write the YAML document to the file.

What is PyYAML used for?

PyYAML is a YAML parser and emitter for Python. Using the PyYAML module, we can perform various actions such as reading and writing complex configuration YAML files, serializing and persisting YMAL data. Use it to convert the YAML file into a Python dictionary.

Can PyYAML parse JSON?

It is often used for configuration files, but can also be used for data exchange. The most used python YAML parser is PyYAML, a library that allows you to load, parse, and write YAML, much like Python's JSON library helps you to work with JSON.


1 Answers

If you use ruamel.yaml ¹, you can relatively easily achieve this, by combining this and this answer here on StackOverlow.

By default ruamel.yaml normalizes to an indent of 2, and drops superfluous quotes. As you don't seem to want that, you have to either explicitly set the indent, or have ruamel.yaml analyse the input, and tell it to preserve quotes:

import sys
import ruamel.yaml
import ruamel.yaml.util

yaml_str = """\
nas:
    mount_dir: '/nvr'
    mount_dirs: ['/mount/data0', '/mount/data1', '/mount/data2']
"""

result, indent, block_seq_indent = ruamel.yaml.util.load_yaml_guess_indent(
    yaml_str, preserve_quotes=True)
result['nas']['mount_dirs'][0] = "haha"
ruamel.yaml.round_trip_dump(result, sys.stdout, indent=indent,
                            block_seq_indent=block_seq_indent)

instead of the load_yaml_guess_indent() invocation you can do:

result = ruamel.yaml.round_trip_load(yaml_str, preserve_quotes=True)
indent = 4
block_sequence_indent = None 

If you want haha to be (single) quoted in the output make it a SingleQuotedScalarString:

result['nas']['mount_dirs'][0] = \
       ruamel.yaml.scalarstring.SingleQuotedScalarString("haha")

with that the output will be:

nas:
    mount_dir: '/nvr'
    mount_dirs: ['haha', '/mount/data1', '/mount/data2']

(given that your short example input has no block style sequences, the block_sequence_indent cannot be determined and will be None)


When using the newer API you have control over the indent of the mapping and sequences seperately:

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=6, offset=3)  # not that that looks nice
data = yaml.load(some_stream)
yaml.dump(data, some_stream)

This will make your YAML formatted consistently if it wasn't so to begin with, and make no further changes after the first round-trip.


¹ Disclaimer: I am the author of that package.

like image 198
Anthon Avatar answered Oct 02 '22 06:10

Anthon