2017-02-15 11 views
2

Моя цель - вставить пару значений ключа в файл YAML, который может быть пустым.Как вставить пару ключевых значений в пустой файл yaml в ruamel.yaml в Python?

Например, мой hiera.yaml (используется в кукольном) файле содержит только три дефиса.

Вот мой код:

#!/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 Алиса 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 

Тогда он работает правильно.

Скажите, пожалуйста, как вставить пару значений ключа (в моем случае a dict) в пустой файл YAML. Примеры официальной страницы ruamel.yaml используют строку doc в качестве образца содержимого YAML, а затем вставляют пары ключ-значение.

ответ

0

Пустой скаляр в документе YAML дает объект null YAML, который загружает в Python, как None:

a: 1 
b: 

Значение ключа b в данных, загруженных из этого будет None.

пустой файл, или пустая строка, из которой загружается ваши данные с помощью ruamel.yaml считается таким же, как файл/строка, содержащая скаляр null:

null 

Если при загрузке, что, вы получите None назад, и вы не можете добавить к нему новые ключи.

Чтобы убедиться, что загруженные вами данные являются dict или подклассом 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() как обычный Dict Python не имеет метода .insert()

Остерегайтесь думал, что элемент верхнего уровня в YAML файл может также быть скаляром (string, integer, datetime и т. д.) или последовательностью (которая загружается как список). Первый, вероятно, не может быть .inserted(), а более поздний (список) принимает только один параметр для .insert()

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 

тоже работает!

+0

Спасибо Oz123 & Anthon. – abhishek

+0

, но ответ Антона более подходит для меня. – abhishek

+0

Oz123 Я немного обеспокоен тем, что вы используете открытие для добавления. IMO никогда не должен делать это с помощью файла YAML, и вы можете сделать файл незагруженным (т. Е. Неправильным YAML), если вы это сделаете. – Anthon