Mercurial > hgrepos > Python > libs > ConfigMix
comparison mixconfig/yaml.py @ 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 | e4c63b4f1568 |
| children |
comparison
equal
deleted
inserted
replaced
| 2:9981a68040b6 | 3:bedc4f95b9e9 |
|---|---|
| 4 | 4 |
| 5 """ | 5 """ |
| 6 | 6 |
| 7 from __future__ import division, print_function, absolute_import | 7 from __future__ import division, print_function, absolute_import |
| 8 | 8 |
| 9 try: | |
| 10 from collections import OrderedDict | |
| 11 except ImportError: | |
| 12 try: | |
| 13 from ordereddict import OrderedDict | |
| 14 except ImportError: | |
| 15 OrderedDict = None | |
| 9 import yaml | 16 import yaml |
| 17 import yaml.constructor | |
| 10 | 18 |
| 11 | 19 |
| 12 __all__ = ["safe_load", "safe_load_all", "load", "load_all"] | 20 __all__ = ["safe_load", "safe_load_all", "load", "load_all"] |
| 13 | 21 |
| 14 | 22 |
| 15 class ConfigLoader(yaml.Loader): | 23 class ConfigLoader(yaml.Loader): |
| 16 | 24 |
| 17 """A YAML loader, which makes all !!str strings to Unicode. Standard | 25 """A YAML loader, which makes all !!str strings to Unicode. Standard |
| 18 PyYAML does this only in the non-ASCII case. | 26 PyYAML does this only in the non-ASCII case. |
| 19 | 27 |
| 28 If an `OrderedDict` implementation is available then all "map" and | |
| 29 "omap" nodes are constructed as `OrderedDict`. | |
| 30 This is against YAML specs but within configuration files it seems | |
| 31 more natural. | |
| 32 | |
| 20 """ | 33 """ |
| 21 | 34 |
| 22 def construct_yaml_str(self, node): | 35 def construct_yaml_str(self, node): |
| 23 return self.construct_scalar(node) | 36 return self.construct_scalar(node) |
| 24 | 37 |
| 38 if OrderedDict: | |
| 39 | |
| 40 # | |
| 41 # From https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 | |
| 42 # (MIT License) | |
| 43 # | |
| 44 | |
| 45 def construct_yaml_map(self, node): | |
| 46 data = OrderedDict() | |
| 47 yield data | |
| 48 value = self.construct_mapping(node) | |
| 49 data.update(value) | |
| 50 | |
| 51 def construct_mapping(self, node, deep=False): | |
| 52 if isinstance(node, yaml.MappingNode): | |
| 53 self.flatten_mapping(node) | |
| 54 else: | |
| 55 raise yaml.constructor.ConstructorError(None, None, | |
| 56 'expected a mapping node, but found %s' % node.id, | |
| 57 node.start_mark) | |
| 58 | |
| 59 mapping = OrderedDict() | |
| 60 for key_node, value_node in node.value: | |
| 61 key = self.construct_object(key_node, deep=deep) | |
| 62 try: | |
| 63 hash(key) | |
| 64 except TypeError as err: | |
| 65 raise yaml.constructor.ConstructorError( | |
| 66 'while constructing a mapping', node.start_mark, | |
| 67 'found unacceptable key (%s)' % err, key_node.start_mark) | |
| 68 value = self.construct_object(value_node, deep=deep) | |
| 69 mapping[key] = value | |
| 70 return mapping | |
| 71 | |
| 25 | 72 |
| 26 ConfigLoader.add_constructor( | 73 ConfigLoader.add_constructor( |
| 27 "tag:yaml.org,2002:str", | 74 "tag:yaml.org,2002:str", |
| 28 ConfigLoader.construct_yaml_str) | 75 ConfigLoader.construct_yaml_str) |
| 76 if OrderedDict: | |
| 77 ConfigLoader.add_constructor( | |
| 78 "tag:yaml.org,2002:map", | |
| 79 ConfigLoader.construct_yaml_map) | |
| 80 ConfigLoader.add_constructor( | |
| 81 "tag:yaml.org,2002:omap", | |
| 82 ConfigLoader.construct_yaml_map) | |
| 29 | 83 |
| 30 | 84 |
| 31 class ConfigSafeLoader(yaml.SafeLoader): | 85 class ConfigSafeLoader(yaml.SafeLoader): |
| 32 | 86 |
| 33 """A safe YAML loader, which makes all !!str strings to Unicode. | 87 """A safe YAML loader, which makes all !!str strings to Unicode. |
| 34 Standard PyYAML does this only in the non-ASCII case. | 88 Standard PyYAML does this only in the non-ASCII case. |
| 35 | 89 |
| 90 If an `OrderedDict` implementation is available then all "map" and | |
| 91 "omap" nodes are constructed as `OrderedDict`. | |
| 92 This is against YAML specs but within configuration files it seems | |
| 93 more natural. | |
| 94 | |
| 36 """ | 95 """ |
| 37 | 96 |
| 38 def construct_yaml_str(self, node): | 97 def construct_yaml_str(self, node): |
| 39 return self.construct_scalar(node) | 98 return self.construct_scalar(node) |
| 40 | 99 |
| 100 if OrderedDict: | |
| 101 | |
| 102 # | |
| 103 # From https://pypi.python.org/pypi/yamlordereddictloader/0.1.1 | |
| 104 # (MIT License) | |
| 105 # | |
| 106 | |
| 107 def construct_yaml_map(self, node): | |
| 108 data = OrderedDict() | |
| 109 yield data | |
| 110 value = self.construct_mapping(node) | |
| 111 data.update(value) | |
| 112 | |
| 113 def construct_mapping(self, node, deep=False): | |
| 114 if isinstance(node, yaml.MappingNode): | |
| 115 self.flatten_mapping(node) | |
| 116 else: | |
| 117 raise yaml.constructor.ConstructorError(None, None, | |
| 118 'expected a mapping node, but found %s' % node.id, | |
| 119 node.start_mark) | |
| 120 | |
| 121 mapping = OrderedDict() | |
| 122 for key_node, value_node in node.value: | |
| 123 key = self.construct_object(key_node, deep=deep) | |
| 124 try: | |
| 125 hash(key) | |
| 126 except TypeError as err: | |
| 127 raise yaml.constructor.ConstructorError( | |
| 128 'while constructing a mapping', node.start_mark, | |
| 129 'found unacceptable key (%s)' % err, key_node.start_mark) | |
| 130 value = self.construct_object(value_node, deep=deep) | |
| 131 mapping[key] = value | |
| 132 return mapping | |
| 133 | |
| 41 | 134 |
| 42 ConfigSafeLoader.add_constructor( | 135 ConfigSafeLoader.add_constructor( |
| 43 "tag:yaml.org,2002:str", | 136 "tag:yaml.org,2002:str", |
| 44 ConfigSafeLoader.construct_yaml_str) | 137 ConfigSafeLoader.construct_yaml_str) |
| 138 if OrderedDict: | |
| 139 ConfigSafeLoader.add_constructor( | |
| 140 "tag:yaml.org,2002:map", | |
| 141 ConfigSafeLoader.construct_yaml_map) | |
| 142 ConfigSafeLoader.add_constructor( | |
| 143 "tag:yaml.org,2002:omap", | |
| 144 ConfigSafeLoader.construct_yaml_map) | |
| 45 | 145 |
| 46 | 146 |
| 47 def load(stream, Loader=ConfigLoader): | 147 def load(stream, Loader=ConfigLoader): |
| 48 return yaml.load(stream, Loader) | 148 return yaml.load(stream, Loader) |
| 49 | 149 |
