0

I want to change only the attribute anotherName from the following yaml file with python.

test.yaml:

--- kind: test scope: not far spec: test1: options: - name: test.com anotherName: example.com empty: [] groupOne: [] emptyList: firstList: [] secondList: [] 

Code (based on this answer)

import yaml with open("test.yaml", 'r') as stream: try: loaded=yaml.safe_load(stream) except yaml.YAMLError as exc: print(exc) temp= loaded['spec']['test1']['options'] for elem in temp: elem['anotherName']='somethingChanged' with open("modified.yaml", 'w') as stream: try: yaml.dump(loaded, stream) print(loaded) except yaml.YAMLError as exc: print(exc) 

The value has been changed, but the code change the order and the structure of the modified.yaml :

#First it misses the thre dashes kind: test scope: not far spec: test1: emptyList: firstList: [] secondList: [] groupOne: [] options: - anotherName: somethingChanged #then the order is changed empty: [] name: test.com 

2 Answers 2

2

If your version of PyYAML is higher than 5.1 you can use sort_keys argument to preserve the order. The only line that needs change is this one:

yaml.dump(loaded, stream, sort_keys=False) 
Sign up to request clarification or add additional context in comments.

Comments

1

you can probably not force a specific output from pyyaml, but if you have such a specific requirement what you want to substitute, then why make the extra hassel of parsing the yml fromat at all. How about reading the file into a string and then making your replacement:

import re # Here you would need to read the file content. I define it here content=""" --- kind: test scope: not far spec: test1: options: - name: test.com anotherName: example.com empty: [] groupOne: [] emptyList: firstList: [] secondList: [] """ print(re.sub(r'anotherName: [^\n]*', 'anotherName: somethingChanged', content)) 

Output:

--- kind: test scope: not far spec: test1: options: - name: test.com anotherName: somethingChanged empty: [] groupOne: [] emptyList: firstList: [] secondList: [] 

4 Comments

If I used your solution, I get TypeError: expected string or bytes-like object because the content is not a string. But if I convert it into a string with re.sub(r'anotherName: [^\n]*', 'anotherName: somethingChanged', str(loaded)), the YAML indentation is lost. Have you a solution about that?
Don't use loaded=yaml.safe_load(stream) to load the file. Instead just loaded=stream.read()
The code is adapted, but now, all the '\n' appears : pastebin.com/vPBpV0DY
You would then need stream.write(re.sub...) instead of dumping it as a yml

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.