thirdparty/google_appengine/google/appengine/api/yaml_listener.py
changeset 109 620f9b141567
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thirdparty/google_appengine/google/appengine/api/yaml_listener.py	Tue Aug 26 21:49:54 2008 +0000
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""PyYAML event listener
+
+Contains class which interprets YAML events and forwards them to
+a handler object.
+"""
+
+
+from google.appengine.api import yaml_errors
+import yaml
+
+
+_EVENT_METHOD_MAP = {
+  yaml.events.StreamStartEvent: 'StreamStart',
+  yaml.events.StreamEndEvent: 'StreamEnd',
+  yaml.events.DocumentStartEvent: 'DocumentStart',
+  yaml.events.DocumentEndEvent: 'DocumentEnd',
+  yaml.events.AliasEvent: 'Alias',
+  yaml.events.ScalarEvent: 'Scalar',
+  yaml.events.SequenceStartEvent: 'SequenceStart',
+  yaml.events.SequenceEndEvent: 'SequenceEnd',
+  yaml.events.MappingStartEvent: 'MappingStart',
+  yaml.events.MappingEndEvent: 'MappingEnd',
+}
+
+
+class EventHandler(object):
+  """Handler interface for parsing YAML files.
+
+  Implement this interface to define specific YAML event handling class.
+  Implementing classes instances are passed to the constructor of
+  EventListener to act as a receiver of YAML parse events.
+  """
+  def StreamStart(self, event, loader):
+    """Handle start of stream event"""
+
+  def StreamEnd(self, event, loader):
+    """Handle end of stream event"""
+
+  def DocumentStart(self, event, loader):
+    """Handle start of document event"""
+
+  def DocumentEnd(self, event, loader):
+    """Handle end of document event"""
+
+  def Alias(self, event, loader):
+    """Handle alias event"""
+
+  def Scalar(self, event, loader):
+    """Handle scalar event"""
+
+  def SequenceStart(self, event, loader):
+    """Handle start of sequence event"""
+
+  def SequenceEnd(self, event, loader):
+    """Handle end of sequence event"""
+
+  def MappingStart(self, event, loader):
+    """Handle start of mappping event"""
+
+  def MappingEnd(self, event, loader):
+    """Handle end of mapping event"""
+
+
+class EventListener(object):
+  """Helper class to re-map PyYAML events to method calls.
+
+  By default, PyYAML generates its events via a Python generator.  This class
+  is a helper that iterates over the events from the PyYAML parser and forwards
+  them to a handle class in the form of method calls.  For simplicity, the
+  underlying event is forwarded to the handler as a parameter to the call.
+
+  This object does not itself produce iterable objects, but is really a mapping
+  to a given handler instance.
+
+    Example use:
+
+      class PrintDocumentHandler(object):
+        def DocumentStart(event):
+          print "A new document has been started"
+
+      EventListener(PrintDocumentHandler()).Parse('''
+        key1: value1
+        ---
+        key2: value2
+        '''
+
+      >>> A new document has been started
+          A new document has been started
+
+  In the example above, the implemented handler class (PrintDocumentHandler)
+  has a single method which reports each time a new document is started within
+  a YAML file.  It is not necessary to subclass the EventListener, merely it
+  receives a PrintDocumentHandler instance.  Every time a new document begins,
+  PrintDocumentHandler.DocumentStart is called with the PyYAML event passed
+  in as its parameter..
+  """
+
+  def __init__(self, event_handler):
+    """Initialize PyYAML event listener.
+
+    Constructs internal mapping directly from event type to method on actual
+    handler.  This prevents reflection being used during actual parse time.
+
+    Args:
+      event_handler: Event handler that will receive mapped events. Must
+        implement at least one appropriate handler method named from
+        the values of the _EVENT_METHOD_MAP.
+
+    Raises:
+      ListenerConfigurationError if event_handler is not an EventHandler.
+    """
+    if not isinstance(event_handler, EventHandler):
+      raise yaml_errors.ListenerConfigurationError(
+        'Must provide event handler of type yaml_listener.EventHandler')
+    self._event_method_map = {}
+    for event, method in _EVENT_METHOD_MAP.iteritems():
+      self._event_method_map[event] = getattr(event_handler, method)
+
+  def HandleEvent(self, event, loader=None):
+    """Handle individual PyYAML event.
+
+    Args:
+      event: Event to forward to method call in method call.
+
+    Raises:
+      IllegalEvent when receives an unrecognized or unsupported event type.
+    """
+    if event.__class__ not in _EVENT_METHOD_MAP:
+      raise yaml_errors.IllegalEvent(
+            "%s is not a valid PyYAML class" % event.__class__.__name__)
+    if event.__class__ in self._event_method_map:
+      self._event_method_map[event.__class__](event, loader)
+
+  def _HandleEvents(self, events):
+    """Iterate over all events and send them to handler.
+
+    This method is not meant to be called from the interface.
+
+    Only use in tests.
+
+    Args:
+      events: Iterator or generator containing events to process.
+    raises:
+      EventListenerParserError when a yaml.parser.ParserError is raised.
+      EventError when an exception occurs during the handling of an event.
+    """
+    for event in events:
+      try:
+        self.HandleEvent(*event)
+      except Exception, e:
+        event_object, loader = event
+        raise yaml_errors.EventError(e, event_object)
+
+  def _GenerateEventParameters(self,
+                               stream,
+                               loader_class=yaml.loader.SafeLoader):
+    """Creates a generator that yields event, loader parameter pairs.
+
+    For use as parameters to HandleEvent method for use by Parse method.
+    During testing, _GenerateEventParameters is simulated by allowing
+    the harness to pass in a list of pairs as the parameter.
+
+    A list of (event, loader) pairs must be passed to _HandleEvents otherwise
+    it is not possible to pass the loader instance to the handler.
+
+    Also responsible for instantiating the loader from the Loader
+    parameter.
+
+    Args:
+      stream: String document or open file object to process as per the
+        yaml.parse method.  Any object that implements a 'read()' method which
+        returns a string document will work.
+      Loader: Loader class to use as per the yaml.parse method.  Used to
+        instantiate new yaml.loader instance.
+
+    Yields:
+      Tuple(event, loader) where:
+        event: Event emitted by PyYAML loader.
+        loader_class: Used for dependency injection.
+    """
+    assert loader_class is not None
+    try:
+      loader = loader_class(stream)
+      while loader.check_event():
+        yield (loader.get_event(), loader)
+    except yaml.error.YAMLError, e:
+      raise yaml_errors.EventListenerYAMLError(e)
+
+  def Parse(self, stream, loader_class=yaml.loader.SafeLoader):
+    """Call YAML parser to generate and handle all events.
+
+    Calls PyYAML parser and sends resulting generator to handle_event method
+    for processing.
+
+    Args:
+      stream: String document or open file object to process as per the
+        yaml.parse method.  Any object that implements a 'read()' method which
+        returns a string document will work with the YAML parser.
+      loader_class: Used for dependency injection.
+    """
+    self._HandleEvents(self._GenerateEventParameters(stream, loader_class))