I am trying to load a YAML file to dictionary then handle dict and safe YAML stream to a file but facing the following issue.
The source y.yaml file includes some string with double quotes :
---
lev1:
lev2:
- name: schema
templates:
- name: temp1
deploy_onpr: "yes"
deploy_cl: "no"
What i got in dest.yaml :
---
lev1:
lev2:
- name: schema
new_item: test
templates:
- deploy_cl: no
deploy_onpr: yes
name: temp1
We can see that quote are removed from yes and no string.
What i expected in dest.yaml is that double quotes should be not delete from strings :
---
lev1:
lev2:
- name: schema
new_item: test
templates:
- deploy_cl: "no"
deploy_onpr: "yes"
name: temp1
the code :
from fnmatch import fnmatch
import json
import os
from json import loads, dumps
import ruamel.yaml
yaml = ruamel.yaml.YAML(typ='safe', pure=True)
yaml.preserve_quotes = True
yaml.explicit_start = True
yaml.default_flow_style = False
yaml.indent(mapping=2, sequence=4, offset=2)
def to_dict(input_ordered_dict):
"""Convert the inventory data stream to dict"""
print(dumps(input_ordered_dict))
return loads(dumps(input_ordered_dict))
def _list_files():
'''
list all yaml files in the yaml directory recursive
'''
pattern = "*.yaml"
in_folder="./"
all_files = []
for path, subdirs, files in os.walk(in_folder):
for name in files:
if fnmatch(name, pattern):
f = os.path.join(path, name)
all_files.append(f)
return all_files
def load_files():
'''
load directory recursive and generate a dict tree
data allocated in the structure under the key "file name"
'''
dict_tree = {}
for sfile in _list_files():
with open(sfile, 'r') as stream:
print(type(yaml))
data_loaded = yaml.load(stream)
print(data_loaded)
dict_tree[sfile] = data_loaded
return dict_tree
load_yaml_files = load_files()
inventoty_data = to_dict(load_yaml_files)
inventoty_data['./y.yaml']["lev1"]["lev2"][0]["new_item"]="test"
new_dict=inventoty_data["./y.yaml"]
dst_file="dest.yaml"
with open(dst_file, 'w') as yaml_file:
yaml.dump(new_dict, yaml_file)
CodePudding user response:
This looks like YAML 1.1, where yes
and no
where supposed to be boolean values (and thus
needed quoting if they were meant as scalar strings).
The preserve_quotes
attribute only works when using the default round-trip loader and dumper
(that uses a subclass of the SafeLoader
, and is also safe to use on unknown YAML sources):
import sys
import ruamel.yaml
from pathlib import Path
yaml = ruamel.yaml.YAML()
yaml.explicit_start = True
yaml.indent(sequence=4, offset=2)
yaml.preserve_quotes = True
data = yaml.load(Path('y.yaml'))
yaml.dump(data, sys.stdout)
which gives:
---
lev1:
lev2:
- name: schema
templates:
- name: temp1
deploy_onpr: "yes"
deploy_cl: "no"
Even if you assign data
as a value to a key in a normal dict, the
special versions of the string created during loading will be preserved and dumped out with quotes.
If you need to add/update some values in Python that need quotes for a string "abc"
then do:
DQ = ruamel.yaml.scalarstring.DoubleQuotesScalarString
some_place_in_your_data_structure = DQ("abc")`
CodePudding user response:
The following code works as expected thanks all for your help
from fnmatch import fnmatch
import json
import os
from json import loads, dumps
import ruamel.yaml
import sys
import ruamel.yaml
from pathlib import Path
ruamel.yaml.representer.RoundTripRepresenter.ignore_aliases = lambda x, y: True
yaml = ruamel.yaml.YAML()
yaml.explicit_start = True
yaml.indent(sequence=4, offset=2)
yaml.preserve_quotes = True
def _list_files():
'''
list all yaml files in the yaml directory recursive
'''
pattern = "*.yaml"
in_folder="./"
all_files = []
for path, subdirs, files in os.walk(in_folder):
for name in files:
if fnmatch(name, pattern):
f = os.path.join(path, name)
all_files.append(f)
return all_files
def load_files():
'''
load directory recursive and generate a dict tree
data allocated in the structure under the key "file name"
'''
dict_tree = {}
for sfile in _list_files():
with open(sfile, 'r') as stream:
data_loaded = yaml.load(stream)
print(data_loaded)
dict_tree[sfile] = data_loaded
return dict_tree
load_yaml_files = load_files()
inventoty_data = load_yaml_files
inventoty_data['./y.yaml']["lev1"]["lev2"][0]["new_item"]="test"
new_dict=inventoty_data["./y.yaml"]
dst_file="dest.yaml"
with open(dst_file, 'w') as yaml_file:
yaml.dump(new_dict, yaml_file)
output:
---
lev1:
lev2:
- name: schema
templates:
- name: temp1
deploy_onpr: "yes"
deploy_cl: "no"
new_item: test