Search code examples
pythonpython-3.xyamlruamel.yamlopenstack-heat

Issue in writing the dictionary into YAML file in python


I want to write dictionary into YAML file and here is what I'm doing as of now

from ruamel.yaml import YAML

Flavor_Details = {'Flavor_Details':{
                  'type': 'OS::Nova::Flavor', 
                  'properties': {
                                 'name': 'test-flavor', 
                                 'extra_specs': {"hw:cpu_policy": 'shared'}, 
                                 'ram': 4096, 
                                 'vcpus': 4, 
                                 'disk': 8
                                }
                 }}

output_section = {
                    'server_public_ip':{
                        'description': 'Floating IP address of server',
                        'value': { 'get_attr': [ 'server_floating_ip', 'ip' ] }
                    }
                }

resources_dict = {}
resources_dict.update(Flavor_Details)
resources_dict.update(output_section)

yaml = YAML(typ= 'safe')

with open('test.yaml', 'w') as outfile:
     yaml.dump(resources_dict,outfile)

And here is the result in YAML file

Flavor_Details:
    properties:
      disk: 8
      extra_specs: {hw:cpu_policy: shared}
      name: test-flavor
      ram: 4096
      vcpus: 4
    type: OS::Nova::Flavor
server_public_ip:
    description: Floating IP address of server
    value:
      get_attr: [server__floating_ip, ip]

But I wanted the result like this:

Flavor_Details:
    properties:
      disk: 8
      extra_specs: {"hw:cpu_policy": shared}
      name: test-flavor
      ram: 4096
      vcpus: 4
    type: OS::Nova::Flavor
server_public_ip:
    description: Floating IP address of server
    value: {get_attr: [server__floating_ip, ip]}

I wanted the "hw:cpu_policy" as a string because of the : between the hw and the cpu_policy and in the value I wanted to be like {get_attr: [server__floating_ip, ip]} this.

Is there any way to get things like that?


Solution

  • You can get what you want, but not by using the safe dumper. The underlying C based code doesnt' allow for the fine grained control that you want.

    You'll need to use the default (round-trip) dumper, which allows for this kind of detailed control, as it needs it to try-and-preserve the layout on round-trips.

    I hope you realise that the quotes around hw:cpu_policy in the YAML file are not necessary according to the YAML specification, but there are some incorrect implementations of YAML parser that have problems with that.

    import sys
    import ruamel.yaml
    
    def Q(s):
        return ruamel.yaml.scalarstring.DoubleQuotedScalarString(s)
    
    def F(*args, **kw):
        x = ruamel.yaml.comments.CommentedMap()
        x.fa.set_flow_style()
        for a in args:
            x.update(a)
        x.update(kw)
        return x
    
    
    Flavor_Details = {'Flavor_Details':{
                      'type': 'OS::Nova::Flavor', 
                      'properties': {
                                     'name': 'test-flavor', 
                                     'extra_specs': F({Q("hw:cpu_policy"): 'shared'}), 
                                     'ram': 4096, 
                                     'vcpus': 4, 
                                     'disk': 8
                                    }
                     }}
    
    output_section = {
                        'server_public_ip':{
                            'description': 'Floating IP address of server',
                            'value': F(get_attr=['server_floating_ip', 'ip'])
                        }
                    }
    
    resources_dict = {}
    resources_dict.update(Flavor_Details)
    resources_dict.update(output_section)
    
    yaml = ruamel.yaml.YAML()
    # yaml.indent(mapping=4, sequence=4, offset=2)
    yaml.dump(resources_dict, sys.stdout)
    

    which gives:

    Flavor_Details:
      type: OS::Nova::Flavor
      properties:
        name: test-flavor
        extra_specs: {"hw:cpu_policy": shared}
        ram: 4096
        vcpus: 4
        disk: 8
    server_public_ip:
      description: Floating IP address of server
      value: {get_attr: [server_floating_ip, ip]}