Convert Python dictionary to yaml
Asked Answered
R

2

39

I have a dictionary, I am converting dictionary to yaml using yaml module in python. But Yaml is not converting properly.

output_data = {
    'resources': [{
        'type': 'compute.v1.instance',
        'name': 'vm-created-by-deployment-manager',
        'properties': {
            'disks': [{
                'deviceName': '$disks_deviceName$',
                'boot': '$disks_boot$',
                'initializeParams': {
                    'sourceImage': '$disks_initializeParams_sourceImage$'
                },
                'autoDelete': '$disks_autoDelete$',
                'type': '$disks_type$'
            }],
            'machineType': '$machineType$',
            'zone': '$zone$',
            'networkInterfaces': [{
                'network': '$networkInterfaces_network$'
            }]
        }
    }]
}

I tried :

import yaml
f = open('meta.yaml', 'w+')
yaml.dump(output_data, f, allow_unicode=True)

I am getting meta.yaml file as following:

resources:
- name: vm-created-by-deployment-manager
  properties:
    disks:
    - autoDelete: $disks_autoDelete$
      boot: $disks_boot$
      deviceName: $disks_deviceName$
      initializeParams: {sourceImage: $disks_initializeParams_sourceImage$}
      type: $disks_type$
    machineType: $machineType$
    networkInterfaces:
    - {network: $networkInterfaces_network$}
    zone: $zone$
  type: compute.v1.instance

Here, {sourceImage: $disks_initializeParams_sourceImage$} and {network: $networkInterfaces_network$} are written like a dictionary. It means inner dictionary contents are not converting to yaml.

I also tried,

output_data = eval(json.dumps(output_data)) 
ff = open('meta.yaml', 'w+')
yaml.dump(output_data, ff, allow_unicode=True)

But getting same yaml file content.

How can I convert a nested dictionary into yaml in Python?

Rive answered 11/10, 2018 at 14:22 Comment(0)
G
28

By default, PyYAML chooses the style of a collection depending on whether it has nested collections. If a collection has nested collections, it will be assigned the block style. Otherwise it will have the flow style.

If you want collections to be always serialized in the block style, set the parameter default_flow_style of dump() to False. For instance,

>> print(yaml.dump(yaml.load(document), default_flow_style=False))
a: 1
b:
   c: 3
   d: 4

Documentation: https://pyyaml.org/wiki/PyYAMLDocumentation

Garling answered 11/10, 2018 at 14:35 Comment(1)
For Python 3.8+ and PyYAML 6.x, the following works print(yaml.dump(document))Aday
P
4

At the time this question was asked, it was default_flow_style=None by default but since PyYaml 5.1, it's been default_flow_style=False by default, so for recent versions of PyYaml, OP's initial code would produce the desired output.

with open('meta.yaml', 'w+') as ff:
    yaml.dump(output_data, ff)

In case you're wondering how one should know which arguments are valid, dump is a wrapper for dump_all, you can use yaml.dump_all for that, e.g. help(yaml.dump_all) shows all valid arguments.

The above code can be written as:

with open('meta.yaml', 'w+') as ff:
    yaml.dump_all([output_data], ff)

dump_all can also return a string if no stream is passed.

s = yaml.dump_all([output_data])
print(s)

resources:
- name: vm-created-by-deployment-manager
  properties:
    disks:
    - autoDelete: $disks_autoDelete$
      boot: $disks_boot$
      deviceName: $disks_deviceName$
      initializeParams:
        sourceImage: $disks_initializeParams_sourceImage$
      type: $disks_type$
    machineType: $machineType$
    networkInterfaces:
    - network: $networkInterfaces_network$
    zone: $zone$
  type: compute.v1.instance
Paramagnet answered 29/2 at 6:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.