-1

I have a few small dictionaries which I would like to include in one yaml file and access each one of them separately with PyYAML. After having some trouble finding out how to write the YAML file, I ended up with this version, where --- is supposed to distinguish the two dictionaries, which are named as elements and as parameters. This was inspired by this post and answer

--- !elements
n: 'N'
p: 'P'
k: 'K'
--- !parameters
ph: 'pH'
org_mat : 'organic matter'

To continue, I created a variable with the name of the path of the file: yaml_fpath = r"\Users\user1\Desktop\yaml_file" and I tried several methods to access the dictionaries, such as:

for item in  yaml.safe_load_all(yaml_fpath):
    print(item)

or

yaml.safe_load(open(yaml_fpath, 'r', encoding = 'utf-8'))

but none does what I need. In fact, I would like to load the file and be able to call each dictionary by each name when I need to use it.

What am I missing from the documentation of PyYAML?

John92
  • 17
  • 5
Newbielp
  • 431
  • 3
  • 16
  • What do you mean by "calling a dictionary by each name"? You have two mappings, one in each document, each get loaded by safe_load_all in an instance of the class registered for the resp. tags. The only thing you can do is check if `item` is an instance of a particular class. Does this have to be PyYAML, ruamel.yaml can load and access this without the need to register classes for the tags, much simpler for what you seem to want to do, i.e. access the mapping as a dictionary? – Anthon Apr 30 '22 at 16:21
  • @Anthon could you please provide an example where the mapped dictionaries above in my example can be accessed, please? I do not seem to make this work and I do not find the right examples online unless I use incorrect keywords. What I need is to be able to call the dictionary "elements" or the dictionary "parameters" and use it accordingly. Thank you in advance! – Newbielp May 10 '22 at 09:19
  • I still don't know what you mean by calling a dicitionary. Instead of Thanking in advance and begging for an example, focus on answering the questions. What might be clear to you doesn't have to be so for others especially if you are using non standard terminology. – Anthon May 10 '22 at 09:55

1 Answers1

1

Assume you have multiple YAML files in a directory that consist of a root level mapping that is tagged:

!elements
n: 'N'
p: 'P'
k: 'K'

If these files have the recommended suffix for YAML files you can combine them using:

import sys
import ruamel.yaml

from pathlib import Path

file_out = Path('out.yaml')

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.explicit_start = True 

data = []
for file_name in Path('.').glob('*.yaml'):
    if file_name.name == file_out.name:
        continue
    print('appending', file_name)
    data.append(yaml.load(file_name))

yaml.dump_all(data, file_out)
print(file_out.read_text())

which gives:

appending file1.yaml
appending file2.yaml
--- !elements
n: 'N'
p: 'P'
k: 'K'
--- !parameters
ph: 'pH'
org_mat: 'organic matter'

There is no need to register any classes that can handle the tag if you use the (default) roundtrip mode. You do have to set explicit_start to get the leading directives end indicator (---, often incorrectly called document separator, although it doesn't have to appear at the beginning of a document). The other directives end indicators are a result of using dump_all() instead of dump().

If you want to access some value, assuming you don't know where it is in out.yaml, but knowing the tag and key, you can do:

import sys
import ruamel.yaml

from pathlib import Path

file_in = Path('out.yaml')

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
data = yaml.load_all(file_in)

my_tag = 'parameters'
my_key = 'org_mat'

for d in data:
    if d.tag.value == '!' + my_tag:
        if my_key in d:
            print('found ->', d[my_key])

which gives:

found -> organic matter
Anthon
  • 69,918
  • 32
  • 186
  • 246
  • Anthon, thank you for your time. I get an ```AttributeError: 'str' object has no attribute 'tag'```. This was exactly my problem before, as I seem unable to pick the dictionary by the tag. With PyYAML I reached that far: ```file = open(path, 'r') ; text = file.read() ; for item in yaml.load_all(text, Loader = yaml.BaseLoader): # no other loaders did the trick ; print(item) # and it prints each dictionary``` But I do not seem able to get the tags or access them somehow. I read that maybe the best way is by using ```enumerate()```. I will try this workaround. – Newbielp May 10 '22 at 11:25
  • The output after `which gives` is captured from running the programs with the two example that you gave. If you insist on using PyYAML, you should have answered that on my first comment, would have spared me writing this answer. – Anthon May 10 '22 at 12:17
  • Anthon, I get the ```Attribute Error``` with ```ruamel.yaml``` and currently reading the documentation (https://readthedocs.org/projects/yaml/downloads/pdf/latest/) exploring all my options to access the dictionary through its tag. There is no need for you to be that contentious though. All the best! – Newbielp May 10 '22 at 12:21
  • Then why are you mentioning PyYAML in your first comment? Instead make sure you have the problematic YAML data in your question, Without that it is guesswork what you are are actually doing, Not even if you have a YAML file with just a scalar string, you get that error ( I tried). – Anthon May 10 '22 at 12:32