Rev 5668: (jelmer) Add some methods to allow lazy loading of hook callbacks. (Jelmer in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Feb 18 18:13:47 UTC 2011


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5668 [merge]
revision-id: pqm at pqm.ubuntu.com-20110218181345-on7vdomzesup6tos
parent: pqm at pqm.ubuntu.com-20110218131200-gaiv52x18519rl5y
parent: jelmer at samba.org-20110218171856-d3903y4at5iud87q
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2011-02-18 18:13:45 +0000
message:
  (jelmer) Add some methods to allow lazy loading of hook callbacks. (Jelmer
   Vernooij)
modified:
  bzrlib/hooks.py                hooks.py-20070325015548-ix4np2q0kd8452au-1
  bzrlib/tests/test_hooks.py     test_hooks.py-20070628030849-89rtsbe5dmer5npz-1
  doc/en/release-notes/bzr-2.4.txt bzr2.4.txt-20110114053217-k7ym9jfz243fddjm-1
=== modified file 'bzrlib/hooks.py'
--- a/bzrlib/hooks.py	2010-09-28 07:34:29 +0000
+++ b/bzrlib/hooks.py	2011-02-18 17:18:56 +0000
@@ -166,14 +166,38 @@
         """
         return self._callable_names.get(a_callable, "No hook name")
 
+    def install_named_hook_lazy(self, hook_name, callable_module,
+        callable_member, name):
+        """Install a_callable in to the hook hook_name lazily, and label it.
+
+        :param hook_name: A hook name. See the __init__ method for the complete
+            list of hooks.
+        :param callable_module: Name of the module in which the callable is
+            present.
+        :param callable_member: Member name of the callable.
+        :param name: A name to associate the callable with, to show users what
+            is running.
+        """
+        try:
+            hook = self[hook_name]
+        except KeyError:
+            raise errors.UnknownHook(self.__class__.__name__, hook_name)
+        try:
+            hook_lazy = getattr(hook, "hook_lazy")
+        except AttributeError:
+            raise errors.UnsupportedOperation(self.install_named_hook_lazy,
+                self)
+        else:
+            hook_lazy(callable_module, callable_member, name)
+
     def install_named_hook(self, hook_name, a_callable, name):
         """Install a_callable in to the hook hook_name, and label it name.
 
-        :param hook_name: A hook name. See the __init__ method of BranchHooks
-            for the complete list of hooks.
+        :param hook_name: A hook name. See the __init__ method for the complete
+            list of hooks.
         :param a_callable: The callable to be invoked when the hook triggers.
             The exact signature will depend on the hook - see the __init__
-            method of BranchHooks for details on each hook.
+            method for details on each hook.
         :param name: A name to associate a_callable with, to show users what is
             running.
         """
@@ -250,6 +274,21 @@
         return (type(other) == type(self) and 
             other.__dict__ == self.__dict__)
 
+    def hook_lazy(self, callback_module, callback_member, callback_label):
+        """Lazily register a callback to be called when this HookPoint fires.
+
+        :param callback_module: Module of the callable to use when this
+            HookPoint fires.
+        :param callback_member: Member name of the callback.
+        :param callback_label: A label to show in the UI while this callback is
+            processing.
+        """
+        obj_getter = registry._LazyObjectGetter(callback_module,
+            callback_member)
+        self._callbacks.append(obj_getter)
+        if callback_label is not None:
+            self._callback_names[obj_getter] = callback_label
+
     def hook(self, callback, callback_label):
         """Register a callback to be called when this HookPoint fires.
 
@@ -257,12 +296,13 @@
         :param callback_label: A label to show in the UI while this callback is
             processing.
         """
-        self._callbacks.append(callback)
+        obj_getter = registry._ObjectGetter(callback)
+        self._callbacks.append(obj_getter)
         if callback_label is not None:
-            self._callback_names[callback] = callback_label
+            self._callback_names[obj_getter] = callback_label
 
     def __iter__(self):
-        return iter(self._callbacks)
+        return (callback.get_obj() for callback in self._callbacks)
 
     def __len__(self):
         return len(self._callbacks)
@@ -272,12 +312,13 @@
         strings.append("<%s(" % type(self).__name__)
         strings.append(self.name)
         strings.append("), callbacks=[")
-        for callback in self._callbacks:
-            strings.append(repr(callback))
+        callbacks = self._callbacks
+        for callback in callbacks:
+            strings.append(repr(callback.get_obj()))
             strings.append("(")
             strings.append(self._callback_names[callback])
             strings.append("),")
-        if len(self._callbacks) == 1:
+        if len(callbacks) == 1:
             strings[-1] = ")"
         strings.append("]>")
         return ''.join(strings)
@@ -322,3 +363,21 @@
         hooks = known_hooks_key_to_object(hook_key)
         segments.append(hooks.docs())
     return '\n'.join(segments)
+
+
+_lazy_hooks = {}
+
+
+def install_lazy_named_hook(hookpoints_module, hookpoints_name, hook_name,
+    a_callable, name):
+    """Install a callable in to a hook lazily, and label it name.
+
+    :param hookpoints_module: Module name of the hook points.
+    :param hookpoints_name: Name of the hook points.
+    :param hook_name: A hook name.
+    :param callable: a callable to call for the hook.
+    :param name: A name to associate a_callable with, to show users what is
+        running.
+    """
+    key = (hookpoints_module, hookpoints_name, hook_name)
+    _lazy_hooks.setdefault(key, []).append((a_callable, name))

=== modified file 'bzrlib/tests/test_hooks.py'
--- a/bzrlib/tests/test_hooks.py	2010-09-21 03:20:09 +0000
+++ b/bzrlib/tests/test_hooks.py	2011-01-20 21:05:23 +0000
@@ -112,6 +112,25 @@
         hooks.install_named_hook('set_rh', None, "demo")
         self.assertEqual("demo", hooks.get_hook_name(None))
 
+    set_rh = lambda: None
+
+    def test_install_named_hook_lazy(self):
+        hooks = Hooks()
+        hooks['set_rh'] = HookPoint("set_rh", "doc", (0, 15), None)
+        hooks.install_named_hook_lazy('set_rh', 'bzrlib.tests.test_hooks',
+            'TestHooks.set_rh', "demo")
+        self.assertEqual(list(hooks['set_rh']), [TestHooks.set_rh])
+
+    def test_install_named_hook_lazy_old(self):
+        # An exception is raised if a lazy hook is raised for
+        # an old style hook point.
+        hooks = Hooks()
+        hooks['set_rh'] = []
+        self.assertRaises(errors.UnsupportedOperation,
+            hooks.install_named_hook_lazy,
+            'set_rh', 'bzrlib.tests.test_hooks', 'TestHooks.set_rh',
+            "demo")
+
 
 class TestHook(tests.TestCase):
 
@@ -144,6 +163,16 @@
         hook.hook(callback, "my callback")
         self.assertEqual([callback], list(hook))
 
+    def lazy_callback():
+        pass
+
+    def test_lazy_hook(self):
+        hook = HookPoint("foo", "no docs", None, None)
+        hook.hook_lazy(
+            "bzrlib.tests.test_hooks", "TestHook.lazy_callback",
+            "my callback")
+        self.assertEqual([TestHook.lazy_callback], list(hook))
+
     def test___repr(self):
         # The repr should list all the callbacks, with names.
         hook = HookPoint("foo", "no docs", None, None)

=== modified file 'doc/en/release-notes/bzr-2.4.txt'
--- a/doc/en/release-notes/bzr-2.4.txt	2011-02-16 17:20:10 +0000
+++ b/doc/en/release-notes/bzr-2.4.txt	2011-02-18 17:05:11 +0000
@@ -145,6 +145,9 @@
   by cacthing them so they can be re-raised in the controlling thread. It's
   available in the ``bzrlib.cethread`` module.  (Vincent Ladeuil)
 
+* ``HookPoint.lazy_hook`` and ``Hooks.install_named_lazy_hook`` can install 
+  hooks for which the callable is loaded lazily.  (Jelmer Vernooij)
+
 Testing
 *******
 




More information about the bazaar-commits mailing list