0

I have a .yml file that looks like this.

nlu:
- intent: greet
  examples: |
    - hey
    - hello
    - hi
    - hello there

Now I want to update this file to add a new intent and example from python. But since the file has a | whenever I update it, the alignment of the file gets messed up.

Like so

with open('nlu.yml', 'r') as yamlfile:
    cur_yaml = yaml.safe_load(yamlfile)
    cur_yaml['nlu'].append({ 'intent': 'name', 'examples': ['first', 'second']})

with open('nlu.yml', 'w') as yamlfile:
     yaml.safe_dump(cur_yaml, yamlfile)
thebenman
  • 1,621
  • 14
  • 35
  • can't you just treat it like a txt file and append whatever you want? ensuring you keep the right indentation of course..or is this a much larger file where that would get tricky – Derek Eden Dec 03 '20 at 04:30
  • @DerekEden it's not a big file at all but I'm thinking wouldn't it be complex to bring the right indentation, | etc if we treat it as a txt and then save it as a yml. or maybe I'm missing something – thebenman Dec 03 '20 at 04:37

1 Answers1

1

| is not a separator. It is the header of a block scalar, meaning the value of examples is a scalar with the content "- hey\n- hello\n- hi\n- hello there\n". To append another sequence item with the same semantic structure, you'll need to do

with open('nlu.yml', 'r') as yamlfile:
    cur_yaml = yaml.safe_load(yamlfile)
    cur_yaml['nlu'].append({ 'intent': 'name', 'examples': "- first\n- second\n"})

Complete working example:

import yaml, sys

input = """
nlu:
- intent: greet
  examples: |
    - hey
    - hello
    - hi
    - hello there
"""

cur_yaml = yaml.safe_load(input)
cur_yaml['nlu'].append({ 'intent': 'name', 'examples': "- first\n- second"})

yaml.safe_dump(cur_yaml, sys.stdout)

This outputs

nlu:
- examples: '- hey

    - hello

    - hi

    - hello there

    '
  intent: greet
- examples: '- first

    - second

    '
  intent: name

Now while this output has the correct YAML semantic, you may dislike the way it's formatted. For an in-depth explanation of why this is happening, see this question.

The takeaway from the answer there for you is that to preserve style, you need to modify the content of your YAML file on a lower level so that Python doesn't forget the original style. I have shown how to do that in this answer. Using the functions defined there, you can reach your desired output like this:

append_to_yaml("input.yaml", "output.yaml", [
  AppendableEvents(["nlu"],
    [MappingStartEvent(None, None, True), key("intent"), key("name"),
     key("examples"), literal_value("- hello there\n- general Kenobi\n"),
     MappingEndEvent()])])

This will transform your YAML input into

nlu:
- intent: greet
  examples: |
    - hey
    - hello
    - hi
    - hello there
- intent: name
  examples: |
    - hello there
    - general Kenobi
flyx
  • 35,506
  • 7
  • 89
  • 126