【问题标题】:How to insert a key value pair in an empty yaml file in ruamel.yaml in Python?如何在 Python 的 ruamel.yaml 中的空 yaml 文件中插入键值对?
【发布时间】:2017-07-03 20:16:25
【问题描述】:

我的目标是在 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内容,然后插入键值对。

【问题讨论】:

    标签: python yaml hiera ruamel.yaml


    【解决方案1】:

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

    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
    

    也有效!

    【讨论】:

    • 感谢 Oz123 和 Anthon。
    • 但是,Anthon 的回答更适合我。
    • Oz123 我有点担心你使用打开追加。 IMO 永远不应该对 YAML 文件执行此操作,如果这样做,您可以使文件不可加载(即不正确的 YAML)。
    【解决方案2】:

    YAML 文档中的空标量为您提供 null YAML 对象,该对象以 None 的形式加载到 Python 中:

    a: 1
    b: 
    

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

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

    null
    

    如果你加载它,你会得到None,你不能向它添加新的密钥。

    确保检查您加载的数据是dict 还是字典的子类(如果您使用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)
    

    您必须使用 CommentedMap(),因为普通的 Python dict 没有方法 .insert()

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

    【讨论】:

      猜你喜欢
      • 2017-04-03
      • 2017-11-02
      • 2021-11-21
      • 1970-01-01
      • 2016-11-10
      • 2013-07-25
      • 2018-10-06
      • 2015-07-19
      • 2019-05-22
      相关资源
      最近更新 更多