Ticket #5: composer.py

File composer.py, 7.9 kB (added by anonymous, 3 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
7 from error import MarkedYAMLError
8 from events import *
9 from nodes import *
10
11 class ComposerError(MarkedYAMLError):
12     pass
13
14 class 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
218 class Composer(BaseComposer):
219     pass
220