3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
21 """PyYAML event listener
23 Contains class which interprets YAML events and forwards them to
29 from google
.appengine
.api
import yaml_errors
35 yaml
.events
.StreamStartEvent
: 'StreamStart',
36 yaml
.events
.StreamEndEvent
: 'StreamEnd',
37 yaml
.events
.DocumentStartEvent
: 'DocumentStart',
38 yaml
.events
.DocumentEndEvent
: 'DocumentEnd',
39 yaml
.events
.AliasEvent
: 'Alias',
40 yaml
.events
.ScalarEvent
: 'Scalar',
41 yaml
.events
.SequenceStartEvent
: 'SequenceStart',
42 yaml
.events
.SequenceEndEvent
: 'SequenceEnd',
43 yaml
.events
.MappingStartEvent
: 'MappingStart',
44 yaml
.events
.MappingEndEvent
: 'MappingEnd',
48 class EventHandler(object):
49 """Handler interface for parsing YAML files.
51 Implement this interface to define specific YAML event handling class.
52 Implementing classes instances are passed to the constructor of
53 EventListener to act as a receiver of YAML parse events.
55 def StreamStart(self
, event
, loader
):
56 """Handle start of stream event"""
58 def StreamEnd(self
, event
, loader
):
59 """Handle end of stream event"""
61 def DocumentStart(self
, event
, loader
):
62 """Handle start of document event"""
64 def DocumentEnd(self
, event
, loader
):
65 """Handle end of document event"""
67 def Alias(self
, event
, loader
):
68 """Handle alias event"""
70 def Scalar(self
, event
, loader
):
71 """Handle scalar event"""
73 def SequenceStart(self
, event
, loader
):
74 """Handle start of sequence event"""
76 def SequenceEnd(self
, event
, loader
):
77 """Handle end of sequence event"""
79 def MappingStart(self
, event
, loader
):
80 """Handle start of mappping event"""
82 def MappingEnd(self
, event
, loader
):
83 """Handle end of mapping event"""
86 class EventListener(object):
87 """Helper class to re-map PyYAML events to method calls.
89 By default, PyYAML generates its events via a Python generator. This class
90 is a helper that iterates over the events from the PyYAML parser and forwards
91 them to a handle class in the form of method calls. For simplicity, the
92 underlying event is forwarded to the handler as a parameter to the call.
94 This object does not itself produce iterable objects, but is really a mapping
95 to a given handler instance.
99 class PrintDocumentHandler(object):
100 def DocumentStart(event):
101 print "A new document has been started"
103 EventListener(PrintDocumentHandler()).Parse('''
109 >>> A new document has been started
110 A new document has been started
112 In the example above, the implemented handler class (PrintDocumentHandler)
113 has a single method which reports each time a new document is started within
114 a YAML file. It is not necessary to subclass the EventListener, merely it
115 receives a PrintDocumentHandler instance. Every time a new document begins,
116 PrintDocumentHandler.DocumentStart is called with the PyYAML event passed
117 in as its parameter..
120 def __init__(self
, event_handler
):
121 """Initialize PyYAML event listener.
123 Constructs internal mapping directly from event type to method on actual
124 handler. This prevents reflection being used during actual parse time.
127 event_handler: Event handler that will receive mapped events. Must
128 implement at least one appropriate handler method named from
129 the values of the _EVENT_METHOD_MAP.
132 ListenerConfigurationError if event_handler is not an EventHandler.
134 if not isinstance(event_handler
, EventHandler
):
135 raise yaml_errors
.ListenerConfigurationError(
136 'Must provide event handler of type yaml_listener.EventHandler')
137 self
._event
_method
_map
= {}
139 for event
, method
in _EVENT_METHOD_MAP
.iteritems():
141 self
._event
_method
_map
[event
] = getattr(event_handler
, method
)
143 def HandleEvent(self
, event
, loader
=None):
144 """Handle individual PyYAML event.
147 event: Event to forward to method call in method call.
150 IllegalEvent when receives an unrecognized or unsupported event type.
153 if event
.__class
__ not in _EVENT_METHOD_MAP
:
154 raise yaml_errors
.IllegalEvent(
155 "%s is not a valid PyYAML class" % event
.__class
__.__name
__)
157 if event
.__class
__ in self
._event
_method
_map
:
158 self
._event
_method
_map
[event
.__class
__](event
, loader
)
160 def _HandleEvents(self
, events
):
161 """Iterate over all events and send them to handler.
163 This method is not meant to be called from the interface.
168 events: Iterator or generator containing events to process.
170 EventListenerParserError when a yaml.parser.ParserError is raised.
171 EventError when an exception occurs during the handling of an event.
175 self
.HandleEvent(*event
)
177 event_object
, loader
= event
178 raise yaml_errors
.EventError(e
, event_object
)
180 def _GenerateEventParameters(self
,
182 loader_class
=yaml
.loader
.SafeLoader
):
183 """Creates a generator that yields event, loader parameter pairs.
185 For use as parameters to HandleEvent method for use by Parse method.
186 During testing, _GenerateEventParameters is simulated by allowing
187 the harness to pass in a list of pairs as the parameter.
189 A list of (event, loader) pairs must be passed to _HandleEvents otherwise
190 it is not possible to pass the loader instance to the handler.
192 Also responsible for instantiating the loader from the Loader
196 stream: String document or open file object to process as per the
197 yaml.parse method. Any object that implements a 'read()' method which
198 returns a string document will work.
199 Loader: Loader class to use as per the yaml.parse method. Used to
200 instantiate new yaml.loader instance.
203 Tuple(event, loader) where:
204 event: Event emitted by PyYAML loader.
205 loader_class: Used for dependency injection.
207 assert loader_class
is not None
209 loader
= loader_class(stream
)
210 while loader
.check_event():
211 yield (loader
.get_event(), loader
)
212 except yaml
.error
.YAMLError
, e
:
213 raise yaml_errors
.EventListenerYAMLError(e
)
215 def Parse(self
, stream
, loader_class
=yaml
.loader
.SafeLoader
):
216 """Call YAML parser to generate and handle all events.
218 Calls PyYAML parser and sends resulting generator to handle_event method
222 stream: String document or open file object to process as per the
223 yaml.parse method. Any object that implements a 'read()' method which
224 returns a string document will work with the YAML parser.
225 loader_class: Used for dependency injection.
227 self
._HandleEvents
(self
._GenerateEventParameters
(stream
, loader_class
))