Rev 4120: Create a single registry of all Hooks classes, removing the test suite knowledge of such hooks and allowing plugins to sensibly and safely define new hooks. in http://people.ubuntu.com/~robertc/baz2.0/pending/Hooks.docs
Robert Collins
robertc at robertcollins.net
Thu Mar 12 02:43:56 GMT 2009
At http://people.ubuntu.com/~robertc/baz2.0/pending/Hooks.docs
------------------------------------------------------------
revno: 4120
revision-id: robertc at robertcollins.net-20090312024346-jx3vpibkrwo1qxar
parent: pqm at pqm.ubuntu.com-20090312001649-6tvc2mmeyw992st3
committer: Robert Collins <robertc at robertcollins.net>
branch nick: Hooks.docs
timestamp: Thu 2009-03-12 13:43:46 +1100
message:
Create a single registry of all Hooks classes, removing the test suite knowledge of such hooks and allowing plugins to sensibly and safely define new hooks.
=== modified file 'NEWS'
--- a/NEWS 2009-03-12 00:16:49 +0000
+++ b/NEWS 2009-03-12 02:43:46 +0000
@@ -50,6 +50,13 @@
IMPROVEMENTS:
+ * All bzr ``Hooks`` classes are now registered in
+ ``bzrlib.hooks.known_hooks``. This removes the separate list from
+ ``bzrlib.tests`` and ensures that all hooks registered there are
+ correctly isolated by the test suite (previously
+ ``MutableTreeHooks`` were not being isolated correctly).
+ (Robert Collins)
+
* ``bzr add`` no longer prints ``add completed`` on success. Failure
still prints an error message. (Robert Collins)
=== modified file 'bzrlib/hooks.py'
--- a/bzrlib/hooks.py 2009-03-11 04:34:21 +0000
+++ b/bzrlib/hooks.py 2009-03-12 02:43:46 +0000
@@ -17,6 +17,7 @@
"""Support for plugin hooking logic."""
from bzrlib.lazy_import import lazy_import
+from bzrlib import registry
from bzrlib.symbol_versioning import deprecated_method, one_five
lazy_import(globals(), """
import textwrap
@@ -28,6 +29,46 @@
""")
+known_hooks = registry.Registry()
+known_hooks.register_lazy(('bzrlib.branch', 'Branch.hooks'), 'bzrlib.branch',
+ 'BranchHooks')
+known_hooks.register_lazy(('bzrlib.commands', 'Command.hooks'),
+ 'bzrlib.commands', 'CommandHooks')
+known_hooks.register_lazy(('bzrlib.mutabletree', 'MutableTree.hooks'),
+ 'bzrlib.mutabletree', 'MutableTreeHooks')
+known_hooks.register_lazy(('bzrlib.smart.client', '_SmartClient.hooks'),
+ 'bzrlib.smart.client', 'SmartClientHooks')
+known_hooks.register_lazy(('bzrlib.smart.server', 'SmartTCPServer.hooks'),
+ 'bzrlib.smart.server', 'SmartServerHooks')
+
+
+def known_hooks_key_to_object((module_name, member_name)):
+ """Convert a known_hooks key to a object.
+
+ :param key: A tuple (module_name, member_name) as found in the keys of
+ the known_hooks registry.
+ :return: The object this specifies.
+ """
+ return registry._LazyObjectGetter(module_name, member_name).get_obj()
+
+
+def known_hooks_key_to_parent_and_attribute((module_name, member_name)):
+ """Convert a known_hooks key to a object.
+
+ :param key: A tuple (module_name, member_name) as found in the keys of
+ the known_hooks registry.
+ :return: The object this specifies.
+ """
+ member_list = member_name.rsplit('.', 1)
+ if len(member_list) == 2:
+ parent_name, attribute = member_list
+ else:
+ parent_name = None
+ attribute = member_name
+ parent = known_hooks_key_to_object((module_name, parent_name))
+ return parent, attribute
+
+
class Hooks(dict):
"""A dictionary mapping hook name to a list of callables.
=== modified file 'bzrlib/registry.py'
--- a/bzrlib/registry.py 2009-02-24 09:13:04 +0000
+++ b/bzrlib/registry.py 2009-03-12 02:43:46 +0000
@@ -62,10 +62,15 @@
return super(_LazyObjectGetter, self).get_obj()
def _do_import(self):
- obj = __import__(self._module_name, globals(), locals(),
- [self._member_name])
- if self._member_name:
- obj = getattr(obj, self._member_name)
+ if self._member_name:
+ segments = self._member_name.split('.')
+ names = segments[0:1]
+ else:
+ names = [self._member_name]
+ obj = __import__(self._module_name, globals(), locals(), names)
+ if self._member_name:
+ for segment in segments:
+ obj = getattr(obj, segment)
self._obj = obj
self._imported = True
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2009-03-10 01:29:23 +0000
+++ b/bzrlib/tests/__init__.py 2009-03-12 02:43:46 +0000
@@ -53,6 +53,7 @@
bzrdir,
debug,
errors,
+ hooks,
memorytree,
osutils,
progress,
@@ -814,22 +815,15 @@
def _clear_hooks(self):
# prevent hooks affecting tests
- import bzrlib.branch
- import bzrlib.smart.client
- import bzrlib.smart.server
- self._preserved_hooks = {
- bzrlib.branch.Branch: bzrlib.branch.Branch.hooks,
- bzrlib.mutabletree.MutableTree: bzrlib.mutabletree.MutableTree.hooks,
- bzrlib.smart.client._SmartClient: bzrlib.smart.client._SmartClient.hooks,
- bzrlib.smart.server.SmartTCPServer: bzrlib.smart.server.SmartTCPServer.hooks,
- bzrlib.commands.Command: bzrlib.commands.Command.hooks,
- }
+ self._preserved_hooks = {}
+ for key, factory in hooks.known_hooks.items():
+ parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
+ current_hooks = hooks.known_hooks_key_to_object(key)
+ self._preserved_hooks[parent] = (name, current_hooks)
self.addCleanup(self._restoreHooks)
- # reset all hooks to an empty instance of the appropriate type
- bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
- bzrlib.smart.client._SmartClient.hooks = bzrlib.smart.client.SmartClientHooks()
- bzrlib.smart.server.SmartTCPServer.hooks = bzrlib.smart.server.SmartServerHooks()
- bzrlib.commands.Command.hooks = bzrlib.commands.CommandHooks()
+ for key, factory in hooks.known_hooks.items():
+ parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
+ setattr(parent, name, factory())
def _silenceUI(self):
"""Turn off UI for duration of test"""
@@ -1288,8 +1282,8 @@
osutils.set_or_unset_env(name, value)
def _restoreHooks(self):
- for klass, hooks in self._preserved_hooks.items():
- setattr(klass, 'hooks', hooks)
+ for klass, (name, hooks) in self._preserved_hooks.items():
+ setattr(klass, name, hooks)
def knownFailure(self, reason):
"""This test has failed for some known reason."""
=== modified file 'bzrlib/tests/test_hooks.py'
--- a/bzrlib/tests/test_hooks.py 2009-03-11 04:34:21 +0000
+++ b/bzrlib/tests/test_hooks.py 2009-03-12 02:43:46 +0000
@@ -16,10 +16,13 @@
"""Tests for the core Hooks logic."""
-from bzrlib import errors
+from bzrlib import branch, errors
from bzrlib.hooks import (
HookPoint,
Hooks,
+ known_hooks,
+ known_hooks_key_to_object,
+ known_hooks_key_to_parent_and_attribute,
)
from bzrlib.errors import (
UnknownHook,
@@ -180,3 +183,33 @@
self.assertEqual(
'<HookPoint(foo), callbacks=[%s(my callback)]>' %
callback_repr, repr(hook))
+
+
+class TestHookRegistry(TestCase):
+
+ def test_items_are_reasonable_keys(self):
+ # All the items in the known_hooks registry need to map from
+ # (module_name, member_name) tuples to the callable used to get an
+ # empty Hooks of for that attribute. This is used to support the test
+ # suite which needs to generate empty hooks (and HookPoints) to ensure
+ # isolation and prevent tests failing spuriously.
+ for key, factory in known_hooks.items():
+ self.assertTrue(callable(factory),
+ "The factory(%r) for %r is not callable" % (factory, key))
+ obj = known_hooks_key_to_object(key)
+ self.assertIsInstance(obj, Hooks)
+ new_hooks = factory()
+ self.assertIsInstance(obj, Hooks)
+ self.assertEqual(type(obj), type(new_hooks))
+
+ def test_known_hooks_key_to_object(self):
+ self.assertIs(branch.Branch.hooks,
+ known_hooks_key_to_object(('bzrlib.branch', 'Branch.hooks')))
+
+ def test_known_hooks_key_to_parent_and_attribute(self):
+ self.assertEqual((branch.Branch, 'hooks'),
+ known_hooks_key_to_parent_and_attribute(
+ ('bzrlib.branch', 'Branch.hooks')))
+ self.assertEqual((branch, 'Branch'),
+ known_hooks_key_to_parent_and_attribute(
+ ('bzrlib.branch', 'Branch')))
More information about the bazaar-commits
mailing list