Loading custom objects with PyYAML

Question:

I have the following YAML document:

!!com.example.hero.YAMLAnimals
animals:
  Land: [Cow, Lion]
  Sea: [Salmon, Cod]

I expected to be able to load the animals object by subclassing YAMLObject.

class YAMLAnimals(yaml.YAMLObject):

    yaml_tag = u'!com.example.hero.YAMLAnimals'

    def __init__(self, animals):
        self.animals = animals

However, when I load the document, I get a ConstructorError.

ConstructorError: could not determine a constructor for the tag 
    'tag:yaml.org,2002:com.example.hero.YAMLAnimals'
Asked By: Johannes

||

Answers:

According to the YAML Reference Card, using the double exclamation point prefix will add tag:yaml.org,2002: to the front of your tag. Instead, use a single exclamation point to properly define your tag.

Animals: !com.example.hero.YAMLAnimals
  Land: [Cow, Lion]
  Sea: [Salmon, Cod]

class YAMLAnimals(yaml.YAMLObject):
    yaml_tag = '!com.example.hero.YAMLAnimals'

Also, as @mgrollins points out, you need to pass the Loader argument to yaml.load.

document = yaml.load(..., Loader = yaml.Loader)

>>> Animals = document['Animals']
>>> print(Animals)
<__main__.YAMLAnimals object at 0x1098c2dd0>
>>> print(vars(Animals))
{'Land': ['Cow', 'Lion'], 'Sea': ['Salmon', 'Cod']}
>>> print(Animals.Land)
['Cow', 'Lion']
>>> print(Animals.Sea)
['Salmon', 'Cod']
Answered By: VietHTran

Consider using yaml.add_constructor when defining your tag; along with a namedtuple.

class YAMLAnimals(collections.namedtuple('Animals', 'Land, Sea')):
    def __new__(cls, loader, node):
        return super().__new__(cls, **loader.construct_mapping(node))

yaml.add_constructor('!com.example.hero.YAMLAnimals', YAMLAnimals)

>>> document = yaml.unsafe_load("""
... Animals: !com.example.hero.YAMLAnimals
...   Land: [Cow, Lion]
...   Sea: [Salmon, Cod]
... """)

>>> print(Animals := document['Animals'])
YAMLAnimals(Land=['Cow', 'Lion'], Sea=['Salmon', 'Cod'])

>>> print(Animals._asdict())
{'Land': ['Cow', 'Lion'], 'Sea': ['Salmon', 'Cod']}
Answered By: Zach Gates
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.