How to save a list of dictionaries to a file with a correct indentation

The goal seems to be simple, but I cannot manage to get the indentation right.

Playbook:

  • name: Saving a list of dictionaries to a file
    gather_facts: false
    hosts:
  • localhost
    strategy: debug
    tasks:
  • name: Saving a list of dictionaries to a file
    vars:
    volumes:
  • class: ‘data’
    id: ‘a61b96e7-427e-493a-993c-c3efc8a16aa1’
    size: ‘500GB’
    type: ‘ssd’
    template:
    src: “volumes.j2”
    dest: “…/files/volumes.yml”

Template:
volumes:
{{ volumes | to_nice_yaml(indent=10) }}

Result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

Expected result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

What is strange is that the indent value has no effect on the result.
Am I doing something wrong or is this an issue with ansible?

You’ve misunderstood what the indent parameter of to_nice_yaml does. It doesn’t shift everything to the right by that much. Rather, it tells how much to indent those things which must be indented, like dictionaries within dictionaries. You don’t have any so it has no effect.

Use the indent filter instead.

volumes:
    {{ volumes | to_nice_yaml() | indent(width=4, first=false) }}

The goal seems to be simple, but I cannot manage to get the indentation right.

Playbook:

  • name: Saving a list of dictionaries to a file
    gather_facts: false
    hosts:
  • localhost
    strategy: debug
    tasks:
  • name: Saving a list of dictionaries to a file
    vars:
    volumes:
  • class: ‘data’
    id: ‘a61b96e7-427e-493a-993c-c3efc8a16aa1’
    size: ‘500GB’
    type: ‘ssd’
    template:
    src: “volumes.j2”
    dest: “…/files/volumes.yml”

Template:
volumes:
{{ volumes | to_nice_yaml(indent=10) }}

Result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

Expected result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

What is strange is that the indent value has no effect on the result.
Am I doing something wrong or is this an issue with ansible?

You received this message because you are subscribed to the Google Groups “Ansible Project” group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-project+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/9147b9cf-c1ab-4102-905c-7f720c4401c0n%40googlegroups.com.

@Todd Lewis
Thanks for pointing me to the right direction. :slight_smile:
Your suggestion is a bit too short:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

Strangely, it indents the first attribute of the list despite ‘first=false’.
With:
volumes:
{{ volumes | to_nice_yaml | indent(width=8, first=false) }}

we get a correct result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

which is close enough, although I don’t understand why we can’t get the original expected result.

It doesn’t help at all that googlegroups uses varying width fonts, especially since whitespace is so important in both YAML and Python.

The docs, as far as I’ve found, never define what to_nice_yaml’s indent parameter controls, but the experiment below shows it only affects the indentation of mapping keys, with the first position in an indentation being either a space or, if this is the first mapping of a list, a dash. The other unfortunate side effect of to_nice_yaml is that it sorts dictionary keys. Both to_yaml and to_nice_yaml are wrappers around calls to yaml.dump() with slightly different parameters. (Particularly, default_flow_style being None and False, respectively, and to_nice_yaml having a default indent of 4, both of which you can override with either to_yaml or to_nice_yaml.)

The indent filter does not indent “the first attribute of the list despite first=false.” The whitespace you see in your output before - class is the literal spaces before the {{.

Save the following as indent.yml and run
ansible-playbook indent.yml && cat ./indent.yml
to see exactly what “it only affects the indentation of mapping keys” means. It’s a lot more subtle than I expected.

- name: Saving a list of dictionaries to a file
  gather_facts: false
  hosts:
  - localhost
  tasks:
  - name: Saving a list of dictionaries to a file
    vars:
      topvar:
        volumes:
        - class: 'data'
          id: 'a61b96e7-427e-493a-993c-c3efc8a16aa1'
          size: '500GB'
          type: 'ssd'
          dict:
            dictd:
              dictd1: 1
              dictd2: 2
            dictc:
            - 111
            - 222
            - dictcdict:
                able: a
                baker: b
                charlie:
                - c1
                - c2
            dictb: beta
            dicta: alpha
    copy:
      content: |
         topvar_indent_2:
         {{ topvar | to_nice_yaml(indent=2) | indent(width=2, first=true) }}
         topvar_no_indent_defaults_to_4:
         {{ topvar | to_nice_yaml(        ) | indent(width=4, first=true) }}
         topvar_indent_8:
         {{ topvar | to_nice_yaml(indent=4) | indent(width=8, first=true) }}
      dest: "./indent_output.yml"

The output is rather long, but I’ll post it here to save you the trouble:

topvar_indent_2:
  volumes:
  - class: data
    dict:
      dicta: alpha
      dictb: beta
      dictc:
      - 111
      - 222
      - dictcdict:
          able: a
          baker: b
          charlie:
          - c1
          - c2
      dictd:
        dictd1: 1
        dictd2: 2
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

topvar_no_indent_defaults_to_4:
    volumes:
    -   class: data
        dict:
            dicta: alpha
            dictb: beta
            dictc:
            - 111
            - 222
            -   dictcdict:
                    able: a
                    baker: b
                    charlie:
                    - c1
                    - c2
            dictd:
                dictd1: 1
                dictd2: 2
        id: a61b96e7-427e-493a-993c-c3efc8a16aa1
        size: 500GB
        type: ssd

topvar_indent_8:
        volumes:
        -   class: data
            dict:
                dicta: alpha
                dictb: beta
                dictc:
                - 111
                - 222
                -   dictcdict:
                        able: a
                        baker: b
                        charlie:
                        - c1
                        - c2
                dictd:
                    dictd1: 1
                    dictd2: 2
            id: a61b96e7-427e-493a-993c-c3efc8a16aa1
            size: 500GB
            type: ssd

@Todd Lewis
Thanks for pointing me to the right direction. :slight_smile:
Your suggestion is a bit too short:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

Strangely, it indents the first attribute of the list despite ‘first=false’.
With:
volumes:
{{ volumes | to_nice_yaml | indent(width=8, first=false) }}

we get a correct result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

which is close enough, although I don’t understand why we can’t get the original expected result.

You’ve misunderstoodwhat the indent parameter of to_nice_yaml does.It doesn’t shift everything to the right by that much. Rather,it tells how much to indent those things which must be indented,like dictionaries within dictionaries. You don’t have any so ithas no effect.

Use the indentfilter instead.

volumes:{{ volumes | to_nice_yaml() | indent(width=4, first=false) }}

The goal seems to be simple, but I cannot manage to get theindentation right.

Playbook:

  • name: Saving a list ofdictionaries to a file
    gather_facts: false
    hosts:
  • localhost
    strategy: debug
    tasks:
  • name: Saving a list of dictionaries to a file
    vars:
    volumes:
  • class: ‘data’
    id:‘a61b96e7-427e-493a-993c-c3efc8a16aa1’
    size: ‘500GB’
    type: ‘ssd’
    template:
    src: “volumes.j2”
    dest: “…/files/volumes.yml”

Template:
volumes:
{{ volumes | to_nice_yaml(indent=10) }}

Result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

Expected result:
volumes:

  • class: data
    id: a61b96e7-427e-493a-993c-c3efc8a16aa1
    size: 500GB
    type: ssd

What is strange is that the indent value has no effect onthe result.
Am I doing something wrong or is this an issue withansible?

…and of course I screwed up my own example. That last bit was supposed to have indent=8, but I had indent=4 instead. Fixed below (maybe).

Also, no idea why googlegroups split my yaml into blocks like it did either. [sigh] I’ve tried to fix that below, too, but I’m not counting on it.