Rev 5306: ``Branch`` formats can now be loaded lazily by registering a in http://bazaar.launchpad.net/~lifeless/bzr/loomsupport
Robert Collins
robertc at robertcollins.net
Fri Jun 18 05:38:08 BST 2010
At http://bazaar.launchpad.net/~lifeless/bzr/loomsupport
------------------------------------------------------------
revno: 5306
revision-id: robertc at robertcollins.net-20100618043750-ij6cdr2fudc71jjs
parent: pqm at pqm.ubuntu.com-20100617173517-cldr2otzfopnb5g1
committer: Robert Collins <robertc at robertcollins.net>
branch nick: loomsupport
timestamp: Fri 2010-06-18 16:37:50 +1200
message:
``Branch`` formats can now be loaded lazily by registering a
``MetaDirBranchFormatFactory`` rather than an actual format. This will
cause the named format class to be loaded only when an enumeration of
formats is needed or when the format string for the object is
encountered. (Robert Collins, Jelmer Vernooij)
=== modified file 'NEWS'
--- a/NEWS 2010-06-17 14:06:36 +0000
+++ b/NEWS 2010-06-18 04:37:50 +0000
@@ -92,6 +92,12 @@
plugins to intercept this even when a ``RemoteBranch`` proxy is in use.
(Robert Collins, #201613)
+* ``Branch`` formats can now be loaded lazily by registering a
+ ``MetaDirBranchFormatFactory`` rather than an actual format. This will
+ cause the named format class to be loaded only when an enumeration of
+ formats is needed or when the format string for the object is
+ encountered. (Robert Collins, Jelmer Vernooij)
+
* Use lazy imports in ``bzrlib/merge.py`` so that plugins like ``news_merge``
do not cause modules to be loaded unnecessarily just because the plugin
registers a merge hook. This improves ``bzr rocks`` time by about 25%
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py 2010-06-17 06:30:22 +0000
+++ b/bzrlib/branch.py 2010-06-18 04:37:50 +0000
@@ -1518,7 +1518,10 @@
try:
transport = a_bzrdir.get_branch_transport(None, name=name)
format_string = transport.get_bytes("format")
- return klass._formats[format_string]
+ format = klass._formats[format_string]
+ if isinstance(format, MetaDirBranchFormatFactory):
+ return format()
+ return format
except errors.NoSuchFile:
raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
except KeyError:
@@ -1529,6 +1532,20 @@
"""Return the current default format."""
return klass._default_format
+ @classmethod
+ def get_formats(klass):
+ """Get all the known formats.
+
+ Warning: This triggers a load of all lazy registered formats: do not
+ use except when that is desireed.
+ """
+ result = []
+ for fmt in klass._formats.values():
+ if isinstance(fmt, MetaDirBranchFormatFactory):
+ fmt = fmt()
+ result.append(fmt)
+ return result
+
def get_reference(self, a_bzrdir, name=None):
"""Get the target reference of the branch in a_bzrdir.
@@ -1671,11 +1688,19 @@
@classmethod
def register_format(klass, format):
- """Register a metadir format."""
+ """Register a metadir format.
+
+ See MetaDirBranchFormatFactory for the ability to register a format
+ without loading the code the format needs until it is actually used.
+ """
klass._formats[format.get_format_string()] = format
# Metadir formats have a network name of their format string, and get
- # registered as class factories.
- network_format_registry.register(format.get_format_string(), format.__class__)
+ # registered as factories.
+ if isinstance(format, MetaDirBranchFormatFactory):
+ network_format_registry.register(format.get_format_string(), format)
+ else:
+ network_format_registry.register(format.get_format_string(),
+ format.__class__)
@classmethod
def set_default_format(klass, format):
@@ -1701,6 +1726,28 @@
return False # by default
+class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
+ """A factory for a BranchFormat object, permitting simple lazy registration."""
+
+ def __init__(self, format_string, module_name, member_name):
+ """Create a MetaDirBranchFormatFactory.
+
+ :param format_string: The format string the format has.
+ :param module_name: Module to load the format class from.
+ :param member_name: Attribute name within the module for the format class.
+ """
+ registry._LazyObjectGetter.__init__(self, module_name, member_name)
+ self._format_string = format_string
+
+ def get_format_string(self):
+ """See BranchFormat.get_format_string."""
+ return self._format_string
+
+ def __call__(self):
+ """Used for network_format_registry support."""
+ return self.get_obj()()
+
+
class BranchHooks(Hooks):
"""A dictionary mapping hook name to a list of callables for branch hooks.
=== modified file 'bzrlib/tests/per_branch/__init__.py'
--- a/bzrlib/tests/per_branch/__init__.py 2010-05-13 15:14:41 +0000
+++ b/bzrlib/tests/per_branch/__init__.py 2010-06-18 04:37:50 +0000
@@ -132,7 +132,7 @@
# Generate a list of branch formats and their associated bzrdir formats to
# use.
combinations = [(format, format._matchingbzrdir) for format in
- BranchFormat._formats.values() + _legacy_formats]
+ BranchFormat.get_formats() + _legacy_formats]
scenarios = make_scenarios(
# None here will cause the default vfs transport server to be used.
None,
=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py 2010-04-23 07:15:23 +0000
+++ b/bzrlib/tests/test_branch.py 2010-06-18 04:37:50 +0000
@@ -136,6 +136,22 @@
return "opened branch."
+class SampleSupportedBranchFormat(_mod_branch.BranchFormat):
+ """A sample supported format."""
+
+ def get_format_string(self):
+ """See BzrBranchFormat.get_format_string()."""
+ return "Sample supported branch format."
+
+ def initialize(self, a_bzrdir, name=None):
+ t = a_bzrdir.get_branch_transport(self, name=name)
+ t.put_bytes('format', self.get_format_string())
+ return 'A branch'
+
+ def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
+ return "opened supported branch."
+
+
class TestBzrBranchFormat(tests.TestCaseWithTransport):
"""Tests for the BzrBranchFormat facility."""
@@ -152,6 +168,17 @@
self.failUnless(isinstance(found_format, format.__class__))
check_format(_mod_branch.BzrBranchFormat5(), "bar")
+ def test_find_format_factory(self):
+ dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
+ SampleSupportedBranchFormat().initialize(dir)
+ factory = _mod_branch.MetaDirBranchFormatFactory(
+ SampleSupportedBranchFormat().get_format_string(),
+ "bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
+ _mod_branch.BranchFormat.register_format(factory)
+ self.addCleanup(_mod_branch.BranchFormat.unregister_format, factory)
+ b = _mod_branch.Branch.open(self.get_url())
+ self.assertEqual(b, "opened supported branch.")
+
def test_find_format_not_branch(self):
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
self.assertRaises(errors.NotBranchError,
@@ -186,6 +213,34 @@
self.make_branch_and_tree('bar')
+#Used by TestMetaDirBranchFormatFactory
+FakeLazyFormat = None
+
+
+class TestMetaDirBranchFormatFactory(tests.TestCase):
+
+ def test_get_format_string_does_not_load(self):
+ """Formats have a static format string."""
+ factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
+ self.assertEqual("yo", factory.get_format_string())
+
+ def test_call_loads(self):
+ # __call__ is used by the network_format_registry interface to get a
+ # Format.
+ global FakeLazyFormat
+ del FakeLazyFormat
+ factory = _mod_branch.MetaDirBranchFormatFactory(None,
+ "bzrlib.tests.test_branch", "FakeLazyFormat")
+ self.assertRaises(AttributeError, factory)
+
+ def test_call_returns_call_of_referenced_object(self):
+ global FakeLazyFormat
+ FakeLazyFormat = lambda:'called'
+ factory = _mod_branch.MetaDirBranchFormatFactory(None,
+ "bzrlib.tests.test_branch", "FakeLazyFormat")
+ self.assertEqual('called', factory())
+
+
class TestBranch67(object):
"""Common tests for both branch 6 and 7 which are mostly the same."""
More information about the bazaar-commits
mailing list