如何使用python更新yaml文件

Che*_*tan 17 python pyyaml

我有一个some.yaml包含以下内容的文件.

    init_config: {}
    instances:
        - host: <IP>
          username: <username>
          password: <password>
Run Code Online (Sandbox Code Playgroud)

应该如下解析和更新yaml文件.

    init_config: {}
    instances:
        - host: 1.2.3.4
          username: Username
          password: Password
Run Code Online (Sandbox Code Playgroud)

如何解析值并适当更新它们?

Ant*_*hon 18

ruamel.yaml包是专门(由我从PyYAML开始)做这种往返,编程,更新的增强.

如果你开始(请注意我删除了额外的初始空格):

init_config: {}
instances:
    - host: <IP>              # update with IP
      username: <username>    # update with user name
      password: <password>    # update with password
Run Code Online (Sandbox Code Playgroud)

并运行:

import ruamel.yaml

file_name = 'input.yaml'
config, ind, bsi = ruamel.yaml.util.load_yaml_guess_indent(open(file_name))

instances = config['instances']
instances[0]['host'] = '1.2.3.4'
instances[0]['username'] = 'Username'
instances[0]['password'] = 'Password'

with open('output.yaml', 'w') as fp:
    yaml.dump(config, fp)
Run Code Online (Sandbox Code Playgroud)

输出将是:

init_config: {}
instances:
    - host: 1.2.3.4           # update with IP
      username: Username      # update with user name
      password: Password      # update with password
Run Code Online (Sandbox Code Playgroud)

映射键(host,usernamepassword),样式和注释的顺序将保留,无需任何进一步的特定操作.

您可以执行手动传统加载,并自行设置缩进值,而不是使用缩进和块序列缩进猜测:

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=6, sequence=4)
with open(file_name) as fp:
    config = yaml.load(fp)
Run Code Online (Sandbox Code Playgroud)

如果你看看这个答案的历史,你可以看到如何使用更有限的PyYAML之类的API来做到这一点.

  • @alkanen 你能将你的陈述阐述成有用的东西吗? (2认同)
  • 当然,对不起。我尝试按照您的示例进行操作,但是 ruamel.yaml 中似乎不再存在 `load_yaml_guess_indent`。如果该方法来自除 ruamel 之外的另一个库,也许您可​​以更新示例以表明这一点?无论哪种方式,代码现在都不会运行,因为 `load_yaml_guess_indent()` 被称为不存在的顶级函数。也就是说,感谢您为我指出正确的方向,以便我可以解决自己的问题! (2认同)

Che*_*tan 8

这是我如何从我提到的上述文件中读取,根据需要解析和更新.

import yaml

fname = "some.yaml"

stream = open(fname, 'r')
data = yaml.load(stream)

data['instances'][0]['host'] = '1.2.3.4'
data['instances'][0]['username'] = 'Username'
data['instances'][0]['password'] = 'Password'

with open(fname, 'w') as yaml_file:
    yaml_file.write( yaml.dump(data, default_flow_style=False))
Run Code Online (Sandbox Code Playgroud)

  • 如果您信任 YAML 文件的来源,请使用 yaml.load(stream, Loader=yaml.FullLoader)`。有关详细信息,请参阅 &lt;https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation&gt; (2认同)

Mar*_*ram 6

我不知道你是否需要 YAML。除了使用 YAML 标签,您似乎对 YAML 文档不感兴趣。那么为什么不使用 Jinja2 或一些模板语言呢?

from jinja2 import Template

tmpl = Template(u'''\
    init_config: {}
    instances:
         - host: {{ IP }}
           username: {{ username }}
           password: {{ password }}
''')

print tmpl.render(
     IP=u"1.2.3.4",
     username=u"Username",
     password=u"Password"
)
Run Code Online (Sandbox Code Playgroud)

我不知道这是否是一个好主意,但是如果您只需要获取更改了某些字段的文件,则您不需要实际解析 YAML 文档,可以直接从模板语言中受益。


奖励:用例

我处理过非常复杂的 YAML 文档,其中有未知的标签

...
  propertiesIDs: { 1, 2, 3, 4 }
  globalID: !myapplication.InterfaceID &primitiveID

replication: !myapplication.replication
  beginDate: 2012-09-10T20:00:03
  endDate: 2020-09-10T20:00:04
  replicant_uuid:
    ? 17169504-B6AB-11E4-8437-36E258BB2172
    ? 206B5842-B6AB-11E4-AAC3-36E258BB2172
...
Run Code Online (Sandbox Code Playgroud)

执行此文档的有效解析既困难又耗时。我只需要填充一些值,并将 YAML 发送到第三方应用程序。因此,与其解析 YAML 或尝试直接使用 pyyaml 生成有效文档,不如直接通过模板生成它更简单(更省时,更不容易出错)。此外,模板语言可以很容易地与循环一起使用来填充动态大小的字段。