pyyaml
pyyaml copied to clipboard
Add method to check mapping key
This PR makes it much easier to generate a safe loader (or a normal loader) that disallows duplicate keys in mappings.
This follows a few points of the Zen of Python:
- Beautiful is better than ugly.
- Simple is better than complex.
- If the implementation is easy to explain, it may be a good idea.
Before (which I'm pretty sure mutates global state):
data = '''
---
foo: bar
foo: qux
'''
def no_duplicates_constructor(loader, node, deep=False):
"""Check for duplicate keys."""
mapping = {}
for key_node, value_node in node.value:
key = loader.construct_object(key_node, deep=deep)
value = loader.construct_object(value_node, deep=deep)
if key in mapping:
raise ConstructorError("while constructing a mapping", node.start_mark,
"found duplicate key (%s)" % key, key_node.start_mark)
mapping[key] = value
return loader.construct_mapping(node, deep)
yaml.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, no_duplicates_constructor, yaml.SafeLoader)
yaml.safe_load(data)
After (does not mutate global state):
import yaml
data = '''
---
foo: bar
foo: qux
'''
class SafeUniqueKeyLoader(yaml.loader.SafeLoader):
def check_mapping_key(self, node, key_node, key, mapping):
super().check_mapping_key(node, key_node, key, mapping)
if key in mapping:
raise ConstructorError("while constructing a mapping", node.start_mark,
"found duplicate key", key_node, start_mark)
yaml.load(data, SafeUniqueKeyLoader)
A few points for your consideration:
- This PR is slightly more complicated, but it might enable better error messages than #502.
- I have no idea where to document this, so the quick docstrings are the only documentation I have made for this. I'm happy to write better and more thorough documentation if you point me to it.
Not sure why tests are failing. They may need to be kicked.