2

我的目标是在可能为空的 YAML 文件中插入一个键值对。

例如,我的hiera.yaml(用于 puppet)文件只包含三个连字符。

这是我的代码:

#!/usr/bin/python
import ruamel.yaml
import sys

def read_file(f):
  with open(f, 'r') as yaml:
    return ruamel.yaml.round_trip_load(yaml)

dict = {}

dict['first_name'] = sys.argv[1]
dict['last_name'] = sys.argv[2]
dict['role'] = sys.argv[3]

data = read_file('hiera.yaml')

pos = len(data)
data.insert(pos, sys.argv[1], dict, None)


ruamel.yaml.round_trip_dump(data, open('hiera.yaml', 'w'), block_seq_indent=1)

我正在运行它:

./alice.py Alice Doe 开发者

我得到如下输出:

Traceback (most recent call last):
  File "./alice.py", line 16, in <module>
    pos = len(data)
TypeError: object of type 'NoneType' has no len()

但是当我的 hiera.yaml 文件不为空时,例如:

$ cat hiera.yaml
john:
$./alice.py Alice Doe Developer
$ cat hiera.yaml
john:
alice:
  first_name: Alice
  last_name: Doe
  role: Developer

然后它可以正常工作。

请告诉我如何将键值对(在我的例子中是一个字典)插入一个空的 YAML 文件。ruamel.yaml 官方页面的示例使用 doc 字符串作为示例 YAML 内容,然后插入键值对。

4

2 回答 2

0

您没有正确处理数据为空的可能性。以下是解决此问题的方法:

import ruamel.yaml
import sys


def read_file(f):
    with open(f, 'r') as yaml:
        return ruamel.yaml.round_trip_load(yaml)

new_dict = {}

new_dict['first_name'] = sys.argv[1]
new_dict['last_name'] = sys.argv[2]
new_dict['role'] = sys.argv[3]

data = read_file('hiera.yaml')
try:
    pos = len(data)
    data.insert(pos, sys.argv[1], dict, None)


except TypeError:
    pass

ruamel.yaml.round_trip_dump(new_dict, open('hiera.yaml', 'a'),
                            block_seq_indent=1)

注意try ... except块。

另请注意,我以附加模式打开文件。否则,如果已经存在,内容将被删除。

演示时间:

 $ cat hiera.yaml 
 Jon:
 $ python test.py  Alice Doe Developer
 cat hiera.yaml 
 Jon:
 first_name: Alice
 role: Developer
 last_name: Doe

这适用于现有数据。现在,让我们用一个空文件进行测试:

 $ rm hiera.yaml 
 $ touch hiera.yaml
 $ python test.py  Alice Doe Developer
 $ cat hiera.yaml 
 first_name: Alice
 role: Developer
 last_name: Doe

也有效!

于 2017-02-15T09:22:24.530 回答
0

YAML 文档中的空标量为您提供了null加载到 Python 中的 YAML 对象None

a: 1
b: 

b从此加载的数据中的键值将是None

使用 ruamel.yaml 从中加载数据的空文件或空字符串被认为与包含标量的文件/字符串相同null

null

如果你加载它,你会None回来,你不能添加新的密钥。

确保检查您加载的数据是dictdict 的一个或一个子类(如果您使用round_trip_load 加载,您将获得一个 ruamel.yaml.comment.CommentedMap),或者检查它是否为 None:

 data = ruamel.yaml.round_trip_load(open('myfile.yaml'))
 if data is None:
     data = ruamel.yaml.comments.CommentedMap()
 data.insert(len(data), key, value)

您必须使用 aCommentedMap()作为普通的 Python dict 没有方法.insert()

请注意,YAML 文件中的顶级项目也可能是标量(字符串、整数、日期时间等)或序列(作为列表加载)。前者可能无法使用.inserted(),而后者(列表)只需要一个参数.insert()

于 2017-02-15T09:41:02.470 回答