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