Will Gordon
Will Gordon

Reputation: 3574

Unable to dump as "pure" YAML

ruamel.yaml==0.15.37
Python 3.6.2 :: Continuum Analytics, Inc.

Current code:

from ruamel.yaml import YAML
import sys


yaml = YAML()
kube_context = yaml.load('''
    apiVersion: v1
    clusters: []
    contexts: []
    current-context: ''
    kind: Config
    preferences: {}
    users: []
''')
kube_context['users'].append({'name': '{username}/{cluster}'.format(username='test', cluster='test'), 'user': {'token': 'test'}})
kube_context['clusters'].append({'name': 'test', 'cluster': {'server': 'URL:443'}})
kube_context['contexts'].append({'name': 'test', 'context': {'user': 'test', 'cluster': 'test'}})

yaml.dump(kube_context, sys.stdout)

My yaml.dump() is producing output that contains the list and dict objects, instead of being fully expanded.

Current output:

apiVersion: v1
clusters: [{name: test, cluster: {server: URL:443}}]
contexts: [{name: test, context: {user: test, cluster: test}}]
current-context: ''
kind: Config
preferences: {}
users: [{name: test/test, user: {token: test}}]

What do I need to do in order to have yaml.dump() output fully expanded?

Expected output:

apiVersion: v1
clusters: 
  - name: test
    cluster: 
      server: URL:443
contexts: 
  - name: test
    context:
      user: test
      cluster: test
current-context: ''
kind: Config
preferences: {}
users: 
  - name: test/test
    user: 
      token: test

Upvotes: 1

Views: 1185

Answers (2)

flyx
flyx

Reputation: 39638

The output is „pure“ YAML. You want the nodes to be presented in block style (indentation-based) as opposed to the current flow style ([]{}-based). Here's how to do that:

yaml = YAML(typ="safe")
yaml.default_flow_style = False

(Note Athon's comment on the typ below; you need to set it to safe or unsafe so that the RoundTripLoader does not set the style of the empty sequences)

Upvotes: 1

Anthon
Anthon

Reputation: 76578

ruamel.yaml, when using the default YAML() or YAML(typ='rt') will preserve the flow- or block style of sequences and mappings. There is no way to make a block style empty sequence or empty mapping and your [] and {} are therefore tagged as flow style when loaded.

Flow style can only contain flow style (whereas block style can contain block style or flow style) (YAML 1.2 spec 8.2.3):

YAML allows flow nodes to be embedded inside block collections (but not vice-versa).

Because of that, the dict/mapping data that you insert in the (flow-style) list/sequence will also be represented as flow-style.

If you want everything to be block style (what you call "expanded" mode), you can explicitly set that by calling the .set_block_style() method on the .fa attribute (which is only available on the collections, hence the try/except):

from ruamel.yaml import YAML
import sys


yaml = YAML()

kube_context = yaml.load('''
    apiVersion: v1
    clusters: []
    contexts: []
    current-context: ''
    kind: Config
    preferences: {}
    users: []
''')
kube_context['users'].append({'name': '{username}/{cluster}'.format(username='test', cluster='test'), 'user': {'token': 'test'}})
kube_context['clusters'].append({'name': 'test', 'cluster': {'server': 'URL:443'}})
kube_context['contexts'].append({'name': 'test', 'context': {'user': 'test', 'cluster': 'test'}})

for k in kube_context:
    try:
        kube_context[k].fa.set_block_style()
    except AttributeError:
        pass

yaml.dump(kube_context, sys.stdout)

this gives:

apiVersion: v1
clusters:
- name: test
  cluster:
    server: URL:443
contexts:
- name: test
  context:
    user: test
    cluster: test
current-context: ''
kind: Config
preferences: {}
users:
- name: test/test
  user:
    token: test

Please note that it is not necessary to set yaml.default_flow_style = False in the default round-trip-mode; and that although block-style has been set for the value of key preferences, it is represented flow style as there is no other way to represent an empty mapping.

Upvotes: 1

Related Questions