Ticket #5: composer.py

File composer.py, 7.9 KB (added by anonymous, 9 years ago)

Patch on file for problem

Line 
1
2__all__ = ['BaseComposer', 'Composer', 'ComposerError']
3
4# This contains revisions to allow recursive loads in this file.
5# All modifications are marked by PKM2006
6
7from error import MarkedYAMLError
8from events import *
9from nodes import *
10
11class ComposerError(MarkedYAMLError):
12    pass
13
14class BaseComposer:
15
16    yaml_resolvers = {}
17
18    def __init__(self):
19        self.all_anchors = {}
20# PKM2006 - unnecessary: self.complete_anchors = {}
21        self.resolver_tags = []
22        self.resolver_paths = []
23
24    def check_node(self):
25        # If there are more documents available?
26        return not self.check_event(StreamEndEvent)
27
28    def get_node(self):
29        # Get the root node of the next document.
30        if not self.check_event(StreamEndEvent):
31            return self.compose_document()
32
33    def __iter__(self):
34        # Iterator protocol.
35        while not self.check_event(StreamEndEvent):
36            yield self.compose_document()
37
38    def compose_document(self):
39
40        # Drop the STREAM-START event.
41        if self.check_event(StreamStartEvent):
42            self.get_event()
43
44        # Drop the DOCUMENT-START event.
45        self.get_event()
46
47        # Compose the root node.
48        node = self.compose_node([])
49
50        # Drop the DOCUMENT-END event.
51        self.get_event()
52
53        self.all_anchors = {}
54# PKM2006 - unnecessary:  self.complete_anchors = {}
55        self.resolver_tags = []
56        self.resolver_paths = []
57        return node
58
59    def increase_resolver_depth(self, path):
60        depth = len(path)
61        tag = None
62        paths = []
63        if not depth:
64            for resolver_path in self.yaml_resolvers.keys():
65                if resolver_path:
66                    paths.append(resolver_path)
67                else:
68                    tag = self.yaml_resolvers[resolver_path]
69        else:
70            base, index = path[-1]
71            if isinstance(index, ScalarNode)    \
72                    and index.tag == self.DEFAULT_SCALAR_TAG:
73                index = index.value
74            elif isinstance(index, Node):
75                index = None
76            for resolver_path in self.resolver_paths[-1]:
77                resolver_index = resolver_path[depth-1]
78                if resolver_index is None or resolver_index == index:
79                    if len(resolver_index) > depth:
80                        paths.append(resolver_path)
81                    else:
82                        tag = self.yaml_resolvers[resolver_path]
83        self.resolver_tags.append(tag)
84        self.resolver_paths.append(paths)
85
86    def decrease_resolver_depth(self):
87        del self.resolver_tags[-1]
88        del self.resolver_paths[-1]
89
90    def compose_node(self, path):
91        if self.check_event(AliasEvent):
92            event = self.get_event()
93            anchor = event.anchor
94            if anchor not in self.all_anchors:
95                raise ComposerError(None, None, "found undefined alias %r"
96                        % anchor.encode('utf-8'), event.start_mark)
97
98# PKM2006 - This code is utterly unsuited for what we want to do.
99# We want to allow recursion.
100#            if anchor not in self.complete_anchors:
101#                collection_event = self.all_anchors[anchor]
102#                raise ComposerError("while composing a collection",
103#                        collection_event.start_mark,
104#                        "found recursive anchor %r" % anchor.encode('utf-8'),
105#                        event.start_mark)
106
107# PKM2006 - now we use the right map here.
108#            return self.complete_anchors[anchor]
109            return self.all_anchors[anchor];
110        self.increase_resolver_depth(path)
111        event = self.peek_event()
112        anchor = event.anchor
113        print "This is an event"
114        print event
115        anchor = event.anchor
116        print "This is the anchor"
117        print anchor
118       
119        if anchor is not None:
120            if anchor in self.all_anchors:
121                raise ComposerError("found duplicate anchor %r; first occurence"
122                        % anchor.encode('utf-8'), self.all_anchors[anchor].start_mark,
123                        "second occurence", event.start_mark)
124            self.all_anchors[anchor] = event
125           
126# PKM2006 - we now add arguments to the compose functions.           
127        if self.check_event(ScalarEvent):
128            node = self.compose_scalar_node(path, anchor) #PKM2006
129        elif self.check_event(SequenceStartEvent):
130            node = self.compose_sequence_node(path, anchor) #PKM2006
131        elif self.check_event(MappingStartEvent):
132            node = self.compose_mapping_node(path, anchor) #PKM2006
133           
134# PKM2006 - we don't need this code any more - we now key nodes
135# by anchors in the appropriate sub-compose function.
136#        if anchor is not None:
137#            self.complete_anchors[anchor] = node
138        self.decrease_resolver_depth()
139        return node
140
141# PKM2006 - extra anchor argument.
142    def compose_scalar_node(self, path, anchor = None):
143        event = self.get_event()
144        tag = self.resolve_scalar(path, event.tag, event.implicit, event.value)
145        ourNode = ScalarNode(tag, event.value,
146                event.start_mark, event.end_mark, style=event.style); #PKM2006
147        if anchor is not None: #PKM2006
148            self.all_anchors[anchor] = ourNode; #PKM2006
149        return ourNode; #PKM2006
150
151# PKM2006 - extra anchor argument.
152    def compose_sequence_node(self, path, anchor = None):
153        start_event = self.get_event()
154        tag = self.resolve_sequence(path, start_event.tag)
155        node = SequenceNode(tag, [],
156                start_event.start_mark, None,
157                flow_style=start_event.flow_style)
158        if anchor is not None: #PKM2006
159            self.all_anchors[anchor] = node; #PKM2006
160        index = 0
161        while not self.check_event(SequenceEndEvent):
162            node.value.append(self.compose_node(path+[(node, index)]))
163            index += 1
164        end_event = self.get_event()
165        node.end_mark = end_event.end_mark
166        return node
167
168# PKM2006 - extra anchor argument.
169    def compose_mapping_node(self, path, anchor = None):
170        start_event = self.get_event()
171        tag = self.resolve_mapping(path, start_event.tag)
172        node = MappingNode(tag, {},
173                start_event.start_mark, None,
174                flow_style=start_event.flow_style)
175        if anchor is not None: #PKM2006
176            self.all_anchors[anchor] = node; #PKM2006
177        while not self.check_event(MappingEndEvent):
178            key_event = self.peek_event()
179            item_key = self.compose_node(path+[(node, None)])
180            item_value = self.compose_node(path+[(node, item_key)])
181            if item_key in node.value:
182                raise ComposerError("while composing a mapping", start_event.start_mark,
183                        "found duplicate key", key_event.start_mark)
184            node.value[item_key] = item_value
185        end_event = self.get_event()
186        node.end_mark = end_event.end_mark
187        return node
188
189    def resolve_scalar(self, path, tag, implicit, value):
190        if implicit:
191            tag = self.detect(value)
192        if tag is None and self.resolver_tags[-1]:
193            tag = self.resolver_tags[-1]
194        if tag is None or tag == u'!':
195            tag = self.DEFAULT_SCALAR_TAG
196        return tag
197
198    def resolve_sequence(self, path, tag):
199        if tag is None and self.resolver_tags[-1]:
200            tag = self.resolver_tags[-1]
201        if tag is None or tag == u'!':
202            tag = self.DEFAULT_SEQUENCE_TAG
203        return tag
204
205    def resolve_mapping(self, path, tag):
206        if tag is None and self.resolver_tags[-1]:
207            tag = self.resolver_tags[-1]
208        if tag is None or tag == u'!':
209            tag = self.DEFAULT_MAPPING_TAG
210        return tag
211
212    def add_resolver(self, tag, path):
213        if not 'yaml_resolvers' in cls.__dict__:
214            cls.yaml_resolvers = cls.yaml_resolvers.copy()
215        cls.yaml_resolvers[tuple(path)] = tag
216    add_resolver = classmethod(add_resolver)
217
218class Composer(BaseComposer):
219    pass
220