Revision: 074a3d1c5243
Author:   Pekka Klärck
Date:     Fri Sep 23 03:41:41 2011
Log:      replaced decorators with metaclass
http://code.google.com/p/robotframework/source/detail?r=074a3d1c5243

Modified:
 /src/robot/output/listeners.py

=======================================
--- /src/robot/output/listeners.py      Fri Sep 23 02:36:53 2011
+++ /src/robot/output/listeners.py      Fri Sep 23 03:41:41 2011
@@ -13,7 +13,6 @@
 #  limitations under the License.

 import inspect
-import sys

 from robot import utils
 from robot.errors import DataError
@@ -25,17 +24,32 @@
     from java.util import HashMap


-def listener_method(method):
-    """Decorator to prevent listeners causing recursion by logging"""
-    def decorated_method(self, *args):
-        if not self._calling_method:
-            self._calling_method = True
-            method(self, *args)
-            self._calling_method = False
-    return decorated_method
-
-
-class Listeners:
+class _RecursionAvoidingMetaclass(type):
+ """Metaclass to wrap listener methods so that they cannot cause recursion.
+
+ Recursion would otherwise happen if one listener logs something and that
+    message is received and logged again by log_message or message method.
+    """
+
+    def __new__(cls, name, bases, dct):
+        for attr, value in dct.items():
+            if not attr.startswith('_') and inspect.isroutine(value):
+                dct[attr] = cls._wrap_listener_method(value)
+        dct['_calling_method'] = False
+        return type.__new__(cls, name, bases, dct)
+
+    @staticmethod
+    def _wrap_listener_method(method):
+        def wrapped(self, *args):
+            if not self._calling_method:
+                self._calling_method = True
+                method(self, *args)
+                self._calling_method = False
+        return wrapped
+
+
+class Listeners(object):
+    __metaclass__ = _RecursionAvoidingMetaclass
     _start_attrs = ['doc', 'starttime', 'longname']
_end_attrs = _start_attrs + ['endtime', 'elapsedtime', 'status', 'message']

@@ -43,7 +57,6 @@
         self._listeners = self._import_listeners(listeners)
         self._running_test = False
         self._setup_or_teardown_type = None
-        self._calling_method = False

     def __nonzero__(self):
         return bool(self._listeners)
@@ -62,7 +75,6 @@
                 LOGGER.info("Details:\n%s" % details)
         return listeners

-    @listener_method
     def start_suite(self, suite):
         for li in self._listeners:
             if li.version == 1:
@@ -74,7 +86,6 @@
                               'totaltests': suite.get_test_count()})
                 li.call_method(li.start_suite, suite.name, attrs)

-    @listener_method
     def end_suite(self, suite):
         for li in self._listeners:
             if li.version == 1:
@@ -85,7 +96,6 @@
                 attrs['statistics'] = suite.get_stat_message()
                 li.call_method(li.end_suite, suite.name, attrs)

-    @listener_method
     def start_test(self, test):
         self._running_test = True
         for li in self._listeners:
@@ -96,7 +106,6 @@
                 attrs['template'] = test.template or ''
                 li.call_method(li.start_test, test.name, attrs)

-    @listener_method
     def end_test(self, test):
         self._running_test = False
         for li in self._listeners:
@@ -107,7 +116,6 @@
                 attrs['template'] = test.template or ''
                 li.call_method(li.end_test, test.name, attrs)

-    @listener_method
     def start_keyword(self, kw):
         for li in self._listeners:
             if li.version == 1:
@@ -117,7 +125,6 @@
                 attrs['type'] = self._get_keyword_type(kw, start=True)
                 li.call_method(li.start_keyword, kw.name, attrs)

-    @listener_method
     def end_keyword(self, kw):
         for li in self._listeners:
             if li.version == 1:
@@ -141,13 +148,11 @@
         return '%s %s' % (('Test' if self._running_test else 'Suite'),
                           kw.type.title())

-    @listener_method
     def log_message(self, msg):
         for li in self._listeners:
             if li.version == 2:
                 li.call_method(li.log_message, self._create_msg_dict(msg))

-    @listener_method
     def message(self, msg):
         for li in self._listeners:
             if li.version == 2:
@@ -157,12 +162,10 @@
         return {'timestamp': msg.timestamp, 'message': msg.message,
                 'level': msg.level, 'html': 'yes' if msg.html else 'no'}

-    @listener_method
     def output_file(self, name, path):
         for li in self._listeners:
             li.call_method(getattr(li, '%s_file' % name.lower()), path)

-    @listener_method
     def close(self):
         for li in self._listeners:
             li.call_method(li.close)

Reply via email to