Modify ↓
Ticket #201 (new defect)
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
Note: See
TracTickets for help on using
tickets.
