python使用Pyyaml并保持格式

时间:2016-10-25 08:54:21

标签: python yaml

这是一个配置文件,我使用PyYAML从它改变一些值,然后我写了一些配置,但它会改变我的格式,它让我困惑。

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

但它改变了我的格式,我该怎么办?

# cat results.conf
nas:
  mount_dir: /nvr
  mount_dirs:
  - haha
  - /mount/data1
  - /mount/data2

3 个答案:

答案 0 :(得分:4)

如果你使用ruamel.yaml¹,你可以通过在StackOverlow上结合thisthis答案来相对轻松地实现这一目标。

默认情况下ruamel.yaml规范化为2的缩进,并删除多余的引号。由于您似乎不想这样,您必须显式设置缩进,或者让ruamel.yaml分析输入,并告诉它保留引号:

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)

而不是load_yaml_guess_indent()调用,您可以这样做:

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

如果您希望haha在输出中引用(单个),请将其设为SingleQuotedScalarString

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

输出将是:

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

(假设您的简短示例输入没有块样式序列,则无法确定block_sequence_indent并且将为None)

使用较新的API时,您可以单独控制映射和序列的缩进:

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)

如果不是这样,那么这将使您的YAML格式一致,并且在第一次往返后不再进行任何进一步的更改。

¹免责声明:我是该套餐的作者。

答案 1 :(得分:1)

ruamel实现了一个往返加载器和转储器,尝试:

import ruamel.yaml
conf = open("results.conf", "r")
results = ruamel.yaml.load(conf, ruamel.yaml.RoundTripLoader)
conf.close()
results['nas']['mount_dirs'][0] = "haha"
with open('/home/zonion/speedio/speedio.conf', 'w') as conf:
  ruamel.yaml.dump(results, conf, ruamel.yaml.RoundTripDumper)

答案 2 :(得分:1)

ruamel.yaml很遗憾,没有完全保留原始格式,并引用了其docs

  

尽管不保留单个的行缩进,但是您可以   为映射和序列指定单独的缩进级别   (计算序列不包括序列的破折号   元素)和其中的块序列破折号的特定偏移量   压痕。

我不知道任何这样做的Python库。

当我需要更改YAML文件而不更改其格式时,我很不情愿地使用regexp(不情愿,因为它几乎和parsing XHTML with it一样糟糕)。

请随时提出更好的解决方案,如果您知道的话,我很乐意学习!