summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Pursehouse <david.pursehouse@sonymobile.com>2012-08-02 12:38:17 +0900
committerDavid Pursehouse <david.pursehouse@sonymobile.com>2012-08-02 17:50:31 +0900
commit8f6f44c15a3ca3d7520b09147c8862e73ad30e11 (patch)
treeeedccd4e67435211b541488f30895b5b90f44619
parentbb6cc231717ce7e77e809c9ed721e7c236bf30cb (diff)
downloadpygerrit-8f6f44c15a3ca3d7520b09147c8862e73ad30e11.tar.gz
Add event factory and refactor event dispatching
Add a new static class GerritEventFactory which provides: - Decorator method to register event names to classes - Method to instantiate an event class based on event name The stream implementation is refactored to use the factory to generate the events. With this change it will be possible to add new event classes without having to modify the stream handler implementation. Change-Id: If1fd0b4f77ead320e98a56301d8266d66dcc8aca
-rw-r--r--pygerrit/events.py46
-rw-r--r--pygerrit/stream.py69
2 files changed, 65 insertions, 50 deletions
diff --git a/pygerrit/events.py b/pygerrit/events.py
index c07979a..4a7200d 100644
--- a/pygerrit/events.py
+++ b/pygerrit/events.py
@@ -4,6 +4,45 @@ from pygerrit.error import GerritError
from pygerrit.models import Account, Approval, Change, Patchset, RefUpdate
+class GerritEventFactory(object):
+
+ """ Gerrit event factory. """
+
+ _events = {}
+
+ @classmethod
+ def register(cls, name):
+ """ Decorator to register the event identified by `name`.
+
+ Raise GerritError if the event is already registered.
+
+ """
+
+ def decorate(klazz):
+ if name in cls._events:
+ raise GerritError("Duplicate event: %s" % name)
+ cls._events[name] = klazz.__name__
+ return klazz
+ return decorate
+
+ @classmethod
+ def create(cls, json_data):
+ """ Create a new event instance.
+
+ Return an instance of the `GerritEvent` subclass from `json_data`
+ Raise GerritError if `json_data` does not contain a `type` key, or
+ no corresponding event is registered.
+
+ """
+ if not "type" in json_data:
+ raise GerritError("`type` not in json_data")
+ name = json_data["type"]
+ if not name in cls._events:
+ raise GerritError("Unknown event: %s" % name)
+ classname = cls._events[name]
+ return globals()[classname](json_data)
+
+
class GerritEvent(object):
""" Gerrit event base class. """
@@ -12,6 +51,7 @@ class GerritEvent(object):
pass
+@GerritEventFactory.register("patchset-created")
class PatchsetCreatedEvent(GerritEvent):
""" Gerrit "patchset-created" event. """
@@ -26,6 +66,7 @@ class PatchsetCreatedEvent(GerritEvent):
raise GerritError("PatchsetCreatedEvent: %s" % e)
+@GerritEventFactory.register("draft-published")
class DraftPublishedEvent(GerritEvent):
""" Gerrit "draft-published" event. """
@@ -40,6 +81,7 @@ class DraftPublishedEvent(GerritEvent):
raise GerritError("DraftPublishedEvent: %s" % e)
+@GerritEventFactory.register("comment-added")
class CommentAddedEvent(GerritEvent):
""" Gerrit "comment-added" event. """
@@ -59,6 +101,7 @@ class CommentAddedEvent(GerritEvent):
raise GerritError("CommentAddedEvent: %s" % e)
+@GerritEventFactory.register("change-merged")
class ChangeMergedEvent(GerritEvent):
""" Gerrit "change-merged" event. """
@@ -73,6 +116,7 @@ class ChangeMergedEvent(GerritEvent):
raise GerritError("ChangeMergedEvent: %s" % e)
+@GerritEventFactory.register("change-abandoned")
class ChangeAbandonedEvent(GerritEvent):
""" Gerrit "change-abandoned" event. """
@@ -88,6 +132,7 @@ class ChangeAbandonedEvent(GerritEvent):
raise GerritError("ChangeAbandonedEvent: %s" % e)
+@GerritEventFactory.register("change-restored")
class ChangeRestoredEvent(GerritEvent):
""" Gerrit "change-restored" event. """
@@ -103,6 +148,7 @@ class ChangeRestoredEvent(GerritEvent):
raise GerritError("ChangeRestoredEvent: %s" % e)
+@GerritEventFactory.register("ref-updated")
class RefUpdatedEvent(GerritEvent):
""" Gerrit "ref-updated" event. """
diff --git a/pygerrit/stream.py b/pygerrit/stream.py
index d59dbb8..9a12d12 100644
--- a/pygerrit/stream.py
+++ b/pygerrit/stream.py
@@ -5,21 +5,10 @@ Class to listen to the Gerrit event stream and dispatch events.
"""
import json
+import logging
-from pygerrit.events import PatchsetCreatedEvent, \
- RefUpdatedEvent, ChangeMergedEvent, CommentAddedEvent, \
- ChangeAbandonedEvent, ChangeRestoredEvent, \
- DraftPublishedEvent
-
-
-# Event types
-CHANGE_MERGED = "change-merged"
-PATCHSET_CREATED = "patchset-created"
-DRAFT_PUBLISHED = "draft-published"
-COMMENT_ADDED = "comment-added"
-CHANGE_ABANDONED = "change-abandoned"
-CHANGE_RESTORED = "change-restored"
-REF_UPDATED = "ref-updated"
+from pygerrit.error import GerritError
+from pygerrit.events import GerritEventFactory
class GerritStreamError(Exception):
@@ -33,15 +22,6 @@ class GerritStream(object):
""" Gerrit events stream handler. """
- # Map the event types to class names.
- _event_dict = {CHANGE_MERGED: "ChangeMergedEvent",
- PATCHSET_CREATED: "PatchsetCreatedEvent",
- DRAFT_PUBLISHED: "DraftPublishedEvent",
- COMMENT_ADDED: "CommentAddedEvent",
- CHANGE_ABANDONED: "ChangeAbandonedEvent",
- CHANGE_RESTORED: "ChangeRestoredEvent",
- REF_UPDATED: "RefUpdatedEvent"}
-
def __init__(self):
self.listeners = []
@@ -70,39 +50,28 @@ class GerritStream(object):
except ValueError:
pass
- def _get_event(self, json_data):
- """ Create a new event from `json_data`.
-
- Return an instance of one of the `GerritEvent` subclasses.
- Raise GerritStreamError if any error occurs.
-
- """
- event_type = json_data["type"]
- if event_type in self._event_dict:
- classname = self._event_dict[event_type]
- try:
- return globals()[classname](json_data)
- except KeyError, e:
- raise GerritStreamError("Error creating event: %s" % e)
+ def stream(self, inputstream):
+ """ Read lines of JSON data from `inputstream` and dispatch events.
- raise GerritStreamError("Unexpected event type `%s`" % event_type)
+ For each line read from `inputstream`, until EOF, parse the line as
+ JSON data, instantiate the corresponding GerritEvent, and dispatch it
+ to the listeners.
- def _dispatch_event(self, event):
- """ Dispatch the `event` to the listeners. """
- for listener in self.listeners:
- listener.on_gerrit_event(event)
+ Raise GerritStreamError on any errors.
- def stream(self, inputstream):
- """ Listen to the `inputstream` and handle JSON objects. """
+ """
try:
- done = 0
- while not done:
+ while 1:
line = inputstream.readline()
- if line:
- data = json.loads(line)
- self._dispatch_event(self._get_event(data))
- else:
+ if not line:
break
+ json_data = json.loads(line)
+ try:
+ event = GerritEventFactory.create(json_data)
+ for listener in self.listeners:
+ listener.on_gerrit_event(event)
+ except GerritError, e:
+ logging.error("Unable to dispatch event: %s", e)
except IOError, e:
raise GerritStreamError("Error reading event stream: %s" % e)
except ValueError, e: