1 # Licensed under the Apache License, Version 2.0 (the "License");
2 # you may not use this file except in compliance with the License.
3 # You may obtain a copy of the License at
5 # http://www.apache.org/licenses/LICENSE-2.0
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS,
9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 # See the License for the specific language governing permissions and
11 # limitations under the License.
13 from ruamel import yaml # @UnresolvedImport
15 from ...utils.collections import OrderedDict
16 from .reader import Reader
17 from .locator import Locator
18 from .exceptions import ReaderSyntaxError
19 from .locator import LocatableString, LocatableInt, LocatableFloat
21 # Add our types to ruamel.yaml
22 yaml.representer.RoundTripRepresenter.add_representer(
23 LocatableString, yaml.representer.RoundTripRepresenter.represent_unicode)
24 yaml.representer.RoundTripRepresenter.add_representer(
25 LocatableInt, yaml.representer.RoundTripRepresenter.represent_int)
26 yaml.representer.RoundTripRepresenter.add_representer(
27 LocatableFloat, yaml.representer.RoundTripRepresenter.represent_float)
29 MERGE_TAG = u'tag:yaml.org,2002:merge'
30 MAP_TAG = u'tag:yaml.org,2002:map'
33 class YamlLocator(Locator):
35 Map for agnostic raw data read from YAML.
38 def add_children(self, node):
39 if isinstance(node, yaml.SequenceNode):
41 for child_node in node.value:
42 self.add_child(child_node)
43 elif isinstance(node, yaml.MappingNode):
45 for k, child_node in node.value:
46 self.add_child(child_node, k)
48 def add_child(self, node, key=None):
49 locator = YamlLocator(self.location, node.start_mark.line + 1, node.start_mark.column + 1)
52 if key.tag == MERGE_TAG:
53 for merge_key, merge_node in node.value:
54 self.add_child(merge_node, merge_key)
56 self.children[key.value] = locator
59 self.children.append(locator)
60 locator.add_children(node)
63 def construct_yaml_map(self, node):
66 value = self.construct_mapping(node)
70 yaml.constructor.SafeConstructor.add_constructor(MAP_TAG, construct_yaml_map)
73 class YamlReader(Reader):
83 # https://bitbucket.org/ruamel/yaml/issues/61/roundtriploader-causes-exceptions-with
84 #yaml_loader = yaml.RoundTripLoader(data)
85 yaml_loader = yaml.SafeLoader(data)
87 node = yaml_loader.get_single_node()
88 locator = YamlLocator(self.loader.location, 0, 0)
90 locator.add_children(node)
91 raw = yaml_loader.construct_document(node)
95 setattr(raw, '_locator', locator)
99 except yaml.parser.MarkedYAMLError as e:
100 context = e.context or 'while parsing'
102 line = e.problem_mark.line
103 column = e.problem_mark.column
104 snippet = e.problem_mark.get_snippet()
105 raise ReaderSyntaxError('YAML %s: %s %s' %
106 (e.__class__.__name__, problem, context),
107 location=self.loader.location,
112 except Exception as e:
113 raise ReaderSyntaxError('YAML: %s' % e, cause=e)