python使用Pyyaml并保持格式

har*_*ldT 7 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()
Run Code Online (Sandbox Code Playgroud)

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

# cat results.conf
nas:
  mount_dir: /nvr
  mount_dirs:
  - haha
  - /mount/data1
  - /mount/data2
Run Code Online (Sandbox Code Playgroud)

Gre*_*cki 6

ruamel.yaml不幸的是,并没有完全保留原始格式,引用其文档

尽管不保留行的单独缩进,但您可以为映射和序列指定单独的缩进级别(序列计数不包括序列元素的破折号)以及该缩进内块序列破折号的特定偏移量。

我不知道有哪个 Python 库可以做到这一点。

当我需要更改 YAML 文件而不触及其格式时,我不情愿地使用 regexp(不情愿地因为它几乎与用它解析 XHTML一样糟糕)。

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


Ant*_*hon 5

如果您使用ruamel.yaml¹,则可以通过在 StackOverlow 上结合答案来相对轻松地实现此目的。

默认情况下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)
Run Code Online (Sandbox Code Playgroud)

load_yaml_guess_indent()您可以执行以下操作,而不是调用:

result = ruamel.yaml.round_trip_load(yaml_str, preserve_quotes=True)
indent = 4
block_sequence_indent = None 
Run Code Online (Sandbox Code Playgroud)

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

result['nas']['mount_dirs'][0] = \
       ruamel.yaml.scalarstring.SingleQuotedScalarString("haha")
Run Code Online (Sandbox Code Playgroud)

输出将是:

nas:
    mount_dir: '/nvr'
    mount_dirs: ['haha', '/mount/data1', '/mount/data2']
Run Code Online (Sandbox Code Playgroud)

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


使用较新的 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)
Run Code Online (Sandbox Code Playgroud)

如果一开始不是这样,这将使您的 YAML 格式保持一致,并且在第一次往返后不再做进一步的更改。


¹免责声明:我是该软件包的作者。