Need help while editing yaml file using python

Viewed 59

I am trying to edit YAML file using python. I am using PyYAML module of python to do this. The YAML file:

version: '1.0'
Fruits:
####################Place Index##################
  #Vendor:
  Vendor:
    location: France
    city: paris
    customers:
     - "Lucy"
    Type:
     Apple : "Red"
     Watermelon : "Small"

I want change the value of "Watermelon" in "Type" under "Fruits" and add a new new_vendor. To do this I am using this code:

#! /usr/bin/python
#! /usr/bin/python3

import yaml
import string
import sys
#import ruamel.yaml

#yaml = ruamel.yaml.YAML()

new_vendor = {
  'New_Vendor':
  {
   'location': 'France',
   'city': 'Nice',
   'Type':
   {
     'Apple' : 'Green',
     'Watermelon' : 'Medium',
     'Pumpkin' : 'Large'
   },
   'customers':
   [
      'Lucy',
      'David'
   ],
  }
          }


with open("compose.yaml", "r+") as comp:
    #data = yaml.load(comp, Loader=yaml.FullLoader)
    data = yaml.load(comp)
    data["Fruits"]["Vendor"]["Type"]["Watermelon"] = "Medium"
    #yaml.dump(license, comp, sort_keys=False)
    yaml.dump(new_vendor, comp)
    yaml.dump(data, comp)
    #yaml.dump_all(data, comp, default_flow_style=False)

And, after executing this code I am getting this result:

version: '1.0'
Fruits:
####################Place Index##################
  #Vendor:
  Vendor:
    location: France
    city: paris
    customers:
     - "Lucy"
    Type:
     Apple : "Red"
     Watermelon : "Small"
New_Vendor:
  Type: {Apple: Green, Pumpkin: Large, Watermelon: Medium}
  city: Nice
  customers: [Lucy, David]
  location: France
Fruits:
  Vendor:
    Type: {Apple: Red, Watermelon: Medium}
    city: paris
    customers: [Lucy]
    location: France
version: '1.0'

But this is not the output I want. Firstly, the first parameter "Vendor" is repeating itself and the change of "Watermelon" value is happening in the repeated parameters not in the original parameters. Also I don't want dictionary and array to be written with {} and [].

How can I resolve this issue?

1 Answers

You should not try to update, or append to an existing YAML file. That is extremely difficult to get right.

Instead load the data, update the data and dump the output. If you do so with ruamel.yaml the block/flow-style will be preserved and new elements default to block-style:

import sys
import ruamel.yaml
from pathlib import Path

    
yaml = ruamel.yaml.YAML()
yaml.indent(sequence=3, offset=1)
yaml.preserve_quotes = True

file_in = Path('compose.yaml')

new_vendor = {
  'New_Vendor':
  {
   'location': 'France',
   'city': 'Nice',
   'Type':
   {
     'Apple' : 'Green',
     'Watermelon' : 'Medium',
     'Pumpkin' : 'Large'
   },
   'customers':
   [
      'Lucy',
      'David'
   ],
  }
}

data = yaml.load(file_in)
data['Fruits'].update(new_vendor)
yaml.dump(data, sys.stdout)

which gives:

version: '1.0'
Fruits:
####################Place Index##################
  #Vendor:
  Vendor:
    location: France
    city: paris
    customers:
     - "Lucy"
    Type:
      Apple: "Red"
      Watermelon: "Small"
  New_Vendor:
    location: France
    city: Nice
    Type:
      Apple: Green
      Watermelon: Medium
      Pumpkin: Large
    customers:
     - Lucy
     - David

If you no longer want the "old" Vendor you can e.g. do:

del data['Fruits']['Vendor']

If you try to do this with PyYAML you'll lose the comments.

Related