Search code examples
pythonpyyaml

pyyaml failed to load python objects


With python 3.8, pyyaml 5.4.1, the simple example used in the official pyyaml documentation for loading a python object https://pyyaml.docsforge.com/master/documentation/#loading-yaml failed to work.

The same example works with pyyaml 5.3.1, 5.3, 5.1.

Here is the complete code adopted from the example above.

class Hero:
    def __init__(self, name, hp, sp):
        self.name = name
        self.hp = hp
        self.sp = sp

    def __repr__(self):
        return "%s(name=%r, hp=%r, sp=%r)" % (
            self.__class__.__name__, self.name, self.hp, self.sp)


def load_class():
    s = """
!!python/object:__main__.Hero
name: Welthyr Syxgon
hp: 1200
sp: 0
"""
    r = yaml.full_load(s)
    print(r)

load_class()

I got an error:

    raise ConstructorError(None, None, yaml.constructor.ConstructorError: could not determine a constructor for the tag 'tag:yaml.org,2002:python/object:__main__.Hero'   in "<unicode string>", line 2, column 1:
    !!python/object:__main__.Hero
    ^

Has anyone seen the same error?


Solution

  • Apparently there was a fix in 5.4 release of PyYaml, you can find more information here: https://github.com/yaml/pyyaml/pull/472.

    However, I don't think that this behaviour is expected, I recommend to open a issue in github.

    Nevertheless I can give you a working solution using yaml.UnsafeLoader (at least for your example):

    import yaml
    
    class Hero:
        def __init__(self, name, hp, sp):
            self.name = name
            self.hp = hp
            self.sp = sp
    
        def __repr__(self):
            return "%s(name=%r, hp=%r, sp=%r)" % (
                self.__class__.__name__, self.name, self.hp, self.sp)
    
    
    def load_class():
        s = """
        !!python/object:__main__.Hero
        name: Welthyr Syxgon
        hp: 1200
        sp: 0
        """
        r = yaml.load(s, Loader=yaml.UnsafeLoader)
        print(r)
    
    load_class()