Modify

Ticket #201 (new defect)

Opened 3 years ago

Last modified 27 hours ago

PyYAML cannot load set with an object of a class with custom __hash__

Reported by: anonymous Owned by: xi
Priority: normal Component: pyyaml
Severity: normal Keywords:
Cc:

Description

I have a class of immutable objects with a hash that depends on creation-time arguments:

class Example(object):
    def __init__(self, name):
        self._name = name
    def __eq__(self, other):
        return isinstance(other, Example) and other._name == self._name
    def __hash__(self):
        return hash(self._name)
    def __repr__(self):
        return "Example(name={!r})".format(self._name)

Unlike pickle, PyYAML is unable to load a set containing such an object:

>>> import pickle
>>> import yaml
>>> ex = Example('test')
>>> source = {ex}
>>> pickle.loads(pickle.dumps(ex))
Example(name='test')
>>> pickle.loads(pickle.dumps(source))
{Example(name='test')}
>>> yaml.load(yaml.dump(ex))
Example(name='test')
>>> yaml.load(yaml.dump(source))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.2/site-packages/yaml/__init__.py", line 72, in load
    return loader.get_single_data()
  File "/usr/lib64/python3.2/site-packages/yaml/constructor.py", line 37, in get_single_data
    return self.construct_document(node)
  File "/usr/lib64/python3.2/site-packages/yaml/constructor.py", line 46, in construct_document
    for dummy in generator:
  File "/usr/lib64/python3.2/site-packages/yaml/constructor.py", line 384, in construct_yaml_set
    value = self.construct_mapping(node)
  File "/usr/lib64/python3.2/site-packages/yaml/constructor.py", line 204, in construct_mapping
    return super().construct_mapping(node, deep=deep)
  File "/usr/lib64/python3.2/site-packages/yaml/constructor.py", line 130, in construct_mapping
    mapping[key] = value
  File "<stdin>", line 7, in __hash__
AttributeError: 'Example' object has no attribute '_name'

The reason is probably that PyYAML tries to add the object to a set before restoring its attributes. It is easy to work around using __getnewargs__ but unexpected as (a) pickle handles the situation correctly and (b) no documentation, either the pickle one or the pyyaml one, mentions the need to restore everything used for hashing with __getnewargs__. So PyYAML probably should either deal correctly with this case, or at least have it mentioned in the documentation.

Attachments

Change History

comment:1 Changed 27 hours ago by maskodok <galihadiputro87@…>

The only thing more I could hope for is documentation of all these features (other than reading through the code).  Cipto Junaedy Is this in process? Can I help? About  Unit Link Terbaik di Indonesia Commonwealth Life Investra Link

View

Add a comment

Modify Ticket

Change Properties
<Author field>
Action
as new
as The resolution will be set. Next status will be 'closed'
to The owner will be changed from xi. Next status will be 'new'
The owner will be changed from xi to anonymous. Next status will be 'assigned'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.