I have a yaml file that also needs to be compatible to an existing black-box software that requires lists to appear on a single line, i.e. not block style, while everything else is expected in block style. pyyaml has no trouble reading this file, but I have not succeeded to write the affected keys containing lists as a string literal via dump() -- though print() shows it gets the right input. Escaping the square brackets also did not help. Here is my present code reduced to the relevant section with just one list:
import sys
import yaml
# given rc or yaml file / lists are one-liners. This needs to be preserved
'''
model:
options:
serial: false
output:
steps: ['apri', 'apos']
transport:
serial: false
observations:
co2:
units: ppm
'''
ymlContents = {
'model':
{'options':{'serial': False},
'output':{
'steps': ['apri', 'apos']
},
'transport':{'serial':False}
},
'observations':
{'co2':{'units': 'ppm'}
}
}
class AsLiteralString(str):
pass
def representAsLiteralString(dumper, data):
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="")
yaml.add_representer(str, representAsLiteralString)
yaml.representer.SafeRepresenter.add_representer(str, representAsLiteralString)
try:
def list2stringConverter(v):
assert isinstance(v, list)
myStr=""+chr(91) # [
for elem in v:
myStr+=chr(39)+elem+chr(39)+"," # # ' ',
rtrnStr=myStr[:-1]+chr(93) #"]"
return (rtrnStr) # rtrnStr is now as desired: steps: ['apri', 'apos']
def list2escapedStringConverter(v):
assert isinstance(v, list)
myStr=""+chr(92)+chr(91) # [
for elem in v:
myStr+=chr(39)+elem+chr(39)+"," # # ' ',
rtrnStr=myStr[:-1]+chr(92)+chr(93) #"]"
return (rtrnStr) # rtrnStr is now as desired: steps: ['apri', 'apos']
s=list2stringConverter(ymlContents['model']['output']['steps'])
sEsc=list2escapedStringConverter(ymlContents['model']['output']['steps'])
print(f"s={s}") # all sweet so far
print(f"sEsc={sEsc}") # all sweet so far
ymlContents['model']['output']['stepsStdStr']=s
ymlContents['model']['output']['stepsLiteralStr']=AsLiteralString(s)
print("standard dump:")
yaml.dump(ymlContents, sys.stdout, default_flow_style=True)
print("dump with default_flow_style=False:")
yaml.dump(ymlContents, sys.stdout, default_flow_style=False)
print("dump with default_flow_style=False and escaped square brackets:")
ymlContents['model']['output']['stepsStdStr']=sEsc
ymlContents['model']['output']['stepsLiteralStr']=AsLiteralString(sEsc)
yaml.dump(ymlContents, sys.stdout, default_flow_style=False)
# with open('outFile.yml', 'w') as outFile:
''' ...but we must have the following output format to be compatible to rc file format:
model:
output:
steps: ['apri', 'apos']
'''
# yaml.dump(ymlContents, outFile) #, default_flow_style=False)
except:
sTxt="Fatal Error: Failed to dump yaml file."
print("Done.")
I read some 20 potential solutions, most of them on stackoverflow, but I could not achieve the desired output. Presently the different approaches from my code produce the following output:
s=['apri','apos']
sEsc=\['apri','apos'\]
standard dump:
{model: {options: {serial: false}, output: {steps: [apri, apos], stepsLiteralStr: !!python/object/new:__main__.AsLiteralString [
'[''apri'',''apos'']'], stepsStdStr: '[''apri'',''apos'']'}, transport: {
serial: false}}, observations: {co2: {units: ppm}}}
dump with default_flow_style=False:
model:
options:
serial: false
output:
steps:
- apri
- apos
stepsLiteralStr: !!python/object/new:__main__.AsLiteralString
- '[''apri'',''apos'']'
stepsStdStr: '[''apri'',''apos'']'
transport:
serial: false
observations:
co2:
units: ppm
dump with default_flow_style=False and escaped square brackets:
model:
options:
serial: false
output:
steps:
- apri
- apos
stepsLiteralStr: !!python/object/new:__main__.AsLiteralString
- \['apri','apos'\]
stepsStdStr: \['apri','apos'\]
transport:
serial: false
observations:
co2:
units: ppm
Done.
I have read that ruamel.yaml might do the trick, but I can't have it on the target system that I'm stuck with.
I have also had a look at Specifying styles for portions of a PyYAML dump, which looked promising, but I need a solution for any list entry at any nesting level, that is to say, I may not know the key name in advance. Thus that solution did not work for me.
Why is it so hard to write that list as a string literal or am I missing something really stupid here? Many thanks for any constructive ideas!