Rev 5308: (lifeless) A lazy-load support glue for Branch formats. (Robert Collins) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Sun Jun 20 23:36:29 BST 2010


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

------------------------------------------------------------
revno: 5308 [merge]
revision-id: pqm at pqm.ubuntu.com-20100620223626-sa26emhs7rjpba4h
parent: pqm at pqm.ubuntu.com-20100618115713-5d0yqkzo14eu94t4
parent: robertc at robertcollins.net-20100620211449-9ns38l9zvdxd1n96
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Sun 2010-06-20 23:36:26 +0100
message:
  (lifeless) A lazy-load support glue for Branch formats. (Robert Collins)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/tests/per_branch/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
  bzrlib/tests/test_branch.py    test_branch.py-20060116013032-97819aa07b8ab3b5
=== modified file 'NEWS'
--- a/NEWS	2010-06-18 11:57:13 +0000
+++ b/NEWS	2010-06-20 22:36:26 +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-20 21:14:49 +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,34 @@
         return False  # by default
 
 
+class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
+    """A factory for a BranchFormat object, permitting simple lazy registration.
+    
+    While none of the built in BranchFormats are lazy registered yet,
+    bzrlib.tests.test_branch.TestMetaDirBranchFormatFactory demonstrates how to
+    use it, and the bzr-loom plugin uses it as well (see
+    bzrlib.plugins.loom.formats).
+    """
+
+    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-20 21:14:49 +0000
@@ -136,6 +136,27 @@
         return "opened branch."
 
 
+# Demonstrating how lazy loading is often implemented:
+# A constant string is created.
+SampleSupportedBranchFormatString = "Sample supported branch format."
+
+# And the format class can then reference the constant to avoid skew.
+class SampleSupportedBranchFormat(_mod_branch.BranchFormat):
+    """A sample supported format."""
+
+    def get_format_string(self):
+        """See BzrBranchFormat.get_format_string()."""
+        return SampleSupportedBranchFormatString
+
+    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 +173,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(
+            SampleSupportedBranchFormatString,
+            "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 +218,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