Mercurial > hgrepos > Python > libs > ConfigMix
changeset 3:bedc4f95b9e9
Use a YAML constructor that automatically creates OrderedDict objects when an OrderedDict implementation is available
| author | Franz Glasner <f.glasner@feldmann-mg.com> |
|---|---|
| date | Tue, 08 Mar 2016 16:25:36 +0100 |
| parents | 9981a68040b6 |
| children | f76d85ccc5b9 |
| files | mixconfig/yaml.py |
| diffstat | 1 files changed, 100 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/mixconfig/yaml.py Tue Mar 08 15:40:37 2016 +0100 +++ b/mixconfig/yaml.py Tue Mar 08 16:25:36 2016 +0100 @@ -6,7 +6,15 @@ from __future__ import division, print_function, absolute_import +try: + from collections import OrderedDict +except ImportError: + try: + from ordereddict import OrderedDict + except ImportError: + OrderedDict = None import yaml +import yaml.constructor __all__ = ["safe_load", "safe_load_all", "load", "load_all"] @@ -17,15 +25,61 @@ """A YAML loader, which makes all !!str strings to Unicode. Standard PyYAML does this only in the non-ASCII case. + If an `OrderedDict` implementation is available then all "map" and + "omap" nodes are constructed as `OrderedDict`. + This is against YAML specs but within configuration files it seems + more natural. + """ def construct_yaml_str(self, node): return self.construct_scalar(node) + if OrderedDict: + + # + # From https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 + # (MIT License) + # + + def construct_yaml_map(self, node): + data = OrderedDict() + yield data + value = self.construct_mapping(node) + data.update(value) + + def construct_mapping(self, node, deep=False): + if isinstance(node, yaml.MappingNode): + self.flatten_mapping(node) + else: + raise yaml.constructor.ConstructorError(None, None, + 'expected a mapping node, but found %s' % node.id, + node.start_mark) + + mapping = OrderedDict() + for key_node, value_node in node.value: + key = self.construct_object(key_node, deep=deep) + try: + hash(key) + except TypeError as err: + raise yaml.constructor.ConstructorError( + 'while constructing a mapping', node.start_mark, + 'found unacceptable key (%s)' % err, key_node.start_mark) + value = self.construct_object(value_node, deep=deep) + mapping[key] = value + return mapping + ConfigLoader.add_constructor( "tag:yaml.org,2002:str", ConfigLoader.construct_yaml_str) +if OrderedDict: + ConfigLoader.add_constructor( + "tag:yaml.org,2002:map", + ConfigLoader.construct_yaml_map) + ConfigLoader.add_constructor( + "tag:yaml.org,2002:omap", + ConfigLoader.construct_yaml_map) class ConfigSafeLoader(yaml.SafeLoader): @@ -33,15 +87,61 @@ """A safe YAML loader, which makes all !!str strings to Unicode. Standard PyYAML does this only in the non-ASCII case. + If an `OrderedDict` implementation is available then all "map" and + "omap" nodes are constructed as `OrderedDict`. + This is against YAML specs but within configuration files it seems + more natural. + """ def construct_yaml_str(self, node): return self.construct_scalar(node) + if OrderedDict: + + # + # From https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 + # (MIT License) + # + + def construct_yaml_map(self, node): + data = OrderedDict() + yield data + value = self.construct_mapping(node) + data.update(value) + + def construct_mapping(self, node, deep=False): + if isinstance(node, yaml.MappingNode): + self.flatten_mapping(node) + else: + raise yaml.constructor.ConstructorError(None, None, + 'expected a mapping node, but found %s' % node.id, + node.start_mark) + + mapping = OrderedDict() + for key_node, value_node in node.value: + key = self.construct_object(key_node, deep=deep) + try: + hash(key) + except TypeError as err: + raise yaml.constructor.ConstructorError( + 'while constructing a mapping', node.start_mark, + 'found unacceptable key (%s)' % err, key_node.start_mark) + value = self.construct_object(value_node, deep=deep) + mapping[key] = value + return mapping + ConfigSafeLoader.add_constructor( "tag:yaml.org,2002:str", ConfigSafeLoader.construct_yaml_str) +if OrderedDict: + ConfigSafeLoader.add_constructor( + "tag:yaml.org,2002:map", + ConfigSafeLoader.construct_yaml_map) + ConfigSafeLoader.add_constructor( + "tag:yaml.org,2002:omap", + ConfigSafeLoader.construct_yaml_map) def load(stream, Loader=ConfigLoader):
