29

I have a YAML file that looks like this:

# Sense 1
- name  : sense1
  type  : float
  value : 31

# sense 2
- name  : sense2
  type  : uint32_t
  value : 1488

# Sense 3
- name  : sense3
  type  : int32_t
  value : 0

- name  : sense4
  type  : int32_t
  value : 0
- name  : sense5
  type  : int32_t
  value : 0
- name  : sense6
  type  : int32_t
  value : 0

I want to use Python to open this file, change some of the values (see above) and close the file. How can I do that ?

For instance I want to set sense2[value]=1234, keeping the YAML output the same.

Anthon
  • 69,918
  • 32
  • 186
  • 246

3 Answers3

41

If you care about preserving the order of your mapping keys, the comment and the white space between the elements of the root-level sequence, e.g. because this file is under revision control, then you should use ruamel.yaml (disclaimer: I am the author of that package).

Assuming your YAML document is in the file input.yaml:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()
# yaml.preserve_quotes = True
with open('input.yaml') as fp:
    data = yaml.load(fp)
for elem in data:
    if elem['name'] == 'sense2':
         elem['value'] = 1234
         break  # no need to iterate further
yaml.dump(data, sys.stdout)

gives:

# Sense 1
- name: sense1
  type: float
  value: 31

# sense 2
- name: sense2
  type: uint32_t
  value: 1234

# Sense 3
- name: sense3
  type: int32_t
  value: 0

- name: sense4
  type: int32_t
  value: 0
- name: sense5
  type: int32_t
  value: 0
- name: sense6
  type: int32_t
  value: 0

This can safely be used on untrusted YAML. The (default) RoundtripLoader is a subclass of the SafeLoader even though it can handle and preserve tags (which it doesn't interpret in the dangerous way PyYAML does when enabling loading of unregistered tags).

Anthon
  • 69,918
  • 32
  • 186
  • 246
  • and `ruamel.yaml.YAML(typ='safe')` for untrusted input – Pat Myron Mar 26 '22 at 05:10
  • @PatMyron I am not sure what you are tyring to say here. The default `ruamel.yaml.YAML()` equals `ruamel.yaml.YAML(typ='rt')` gets you a subclass of the `SafeLoader` that can deal with tags (but not in the way the untrusted `Loader` does) which can safely be used on untrusted sources, without losing comments/tags etc. – Anthon Mar 26 '22 at 07:05
  • unfortunately my ymal is totally changed and the comments are disappeared though i only wanted to change one simple line of version – dang Jul 11 '22 at 07:05
  • @dang `ruamel.yaml` doesn't support the ymal format. – Anthon Jul 11 '22 at 07:13
34
import yaml

with open("data.yaml") as f:
     list_doc = yaml.safe_load(f)

for sense in list_doc:
    if sense["name"] == "sense2":
         sense["value"] = 1234

with open("data.yaml", "w") as f:
    yaml.dump(list_doc, f)
Kartik Chugh
  • 1,104
  • 14
  • 28
jwilner
  • 6,348
  • 6
  • 35
  • 47
  • 3
    Thanks jwilner - It's actually change the format of the Yaml (not wanted !) e.g.- got {name: sense_base_temp, type: float, value: 31} - {name: sense_common_delay, type: uint32_t, value: 1488} - {name: sense1, type: int32_t, value: 0} - {name: sense2, type: int32_t, value: 0} - {name: sense3, type: int32_t, value: 0} - {name: sense4, type: int32_t, value: 0} – Tzimkiyahoo Bar Kozyva Apr 09 '15 at 05:22
  • Ah, I get what you want. I think you want to call `yaml.dump` with the keyword argument `default_flow_style=False` – jwilner Apr 09 '15 at 05:27
  • 1
    Yep - now it is fine !! - but all comments in the original Yaml where gone... (:<) - is there a way to read - modify- save (like a any text file) without change any other issue? – Tzimkiyahoo Bar Kozyva Apr 09 '15 at 05:32
  • 1
    Doesn't look like you can preserve comments: http://stackoverflow.com/questions/7255885/save-dump-a-yaml-file-with-comments-in-pyyaml. If your changes are simple, you could just read the file as a string and use string manipulation. – jwilner Apr 09 '15 at 05:42
  • There is almost never a need to use the unsafe `load()`, certainly not here. You should always use `safe_load()` instead. `sense_2` is nowhere in the OPs input, so I assumed that to be a typo. You can certainly preserve comments, see the most upvoted answer to the question you link to (posted long before this answer). – Anthon Apr 11 '18 at 06:36
  • 1
    As of version 5.1, you should use `yaml.load(, Loader=yaml.FullLoader)` to avoid warnings. – stefanbschneider Apr 04 '19 at 11:54
0

This script allows you to update specific fields in a YAML file by providing field-value pairs as command-line arguments.

https://github.com/ataha/python-snippets/blob/master/YAML_modifier/YAML_Modifier.py

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/34660700) – Chenmunka Jul 11 '23 at 20:39