Rev 2763: * ``bzr plugins`` now lists the version number for each plugin in square in http://people.ubuntu.com/~robertc/baz2.0/plugin-versions

Robert Collins robertc at robertcollins.net
Wed Aug 29 02:17:29 BST 2007


At http://people.ubuntu.com/~robertc/baz2.0/plugin-versions

------------------------------------------------------------
revno: 2763
revision-id: robertc at robertcollins.net-20070829011653-lb22o8no67g4y7yp
parent: pqm at pqm.ubuntu.com-20070828155202-pcq659o80mx4f4p3
committer: Robert Collins <robertc at robertcollins.net>
branch nick: plugin-versions
timestamp: Wed 2007-08-29 11:16:53 +1000
message:
   * ``bzr plugins`` now lists the version number for each plugin in square
     brackets after the path. (Robert Collins, #125421)
   * ``bzrlib.plugin.all_plugins`` has been deprecated in favour of
     ``bzrlib.plugin.plugins()`` which returns PlugIn objects that provide
     useful functionality for determining the path of a plugin, its tests, and
     its version information. (Robert Collins)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/plugin.py               plugin.py-20050622060424-829b654519533d69
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/test_plugins.py   plugins.py-20050622075746-32002b55e5e943e9
=== modified file 'NEWS'
--- a/NEWS	2007-08-28 14:35:10 +0000
+++ b/NEWS	2007-08-29 01:16:53 +0000
@@ -23,6 +23,9 @@
 
   BUG FIXES:
 
+   * ``bzr plugins`` now lists the version number for each plugin in square
+     brackets after the path. (Robert Collins, #125421)
+
     * Suppress warning "integer argument expected, got float" from Paramiko,
       which sometimes caused false test failures.  (Martin Pool)
 
@@ -96,6 +99,11 @@
 
   INTERNALS:
 
+   * ``bzrlib.plugin.all_plugins`` has been deprecated in favour of
+     ``bzrlib.plugin.plugins()`` which returns PlugIn objects that provide
+     useful functionality for determining the path of a plugin, its tests, and
+     its version information. (Robert Collins)
+
    * New trace function ``mutter_callsite`` will print out a subset of the
      stack to the log, which can be useful for gathering debug details.
      (Robert Collins)

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2007-08-25 12:54:38 +0000
+++ b/bzrlib/builtins.py	2007-08-29 01:16:53 +0000
@@ -3235,15 +3235,9 @@
     def run(self):
         import bzrlib.plugin
         from inspect import getdoc
-        for name, plugin in bzrlib.plugin.all_plugins().items():
-            if getattr(plugin, '__path__', None) is not None:
-                print plugin.__path__[0]
-            elif getattr(plugin, '__file__', None) is not None:
-                print plugin.__file__
-            else:
-                print repr(plugin)
-                
-            d = getdoc(plugin)
+        for name, plugin in bzrlib.plugin.plugins().items():
+            print plugin.path(), "[%s]" % plugin.__version__
+            d = getdoc(plugin.module)
             if d:
                 print '\t', d.split('\n')[0]
 

=== modified file 'bzrlib/plugin.py'
--- a/bzrlib/plugin.py	2007-08-28 04:34:10 +0000
+++ b/bzrlib/plugin.py	2007-08-29 01:16:53 +0000
@@ -42,10 +42,11 @@
 from bzrlib import (
     config,
     osutils,
-    plugins,
     )
+from bzrlib import plugins as _mod_plugins
 """)
 
+from bzrlib.symbol_versioning import deprecated_function, zero_ninetyone
 from bzrlib.trace import mutter, warning, log_exception_quietly
 
 
@@ -60,12 +61,12 @@
     return DEFAULT_PLUGIN_PATH
 
 
+ at deprecated_function(zero_ninetyone)
 def all_plugins():
     """Return a dictionary of the plugins."""
     result = {}
-    for name, plugin in plugins.__dict__.items():
-        if isinstance(plugin, types.ModuleType):
-            result[name] = plugin
+    for name, plugin in plugins().items():
+        result[name] = plugin.module
     return result
 
 
@@ -90,8 +91,8 @@
     # it tries to import modules.
     path = map(_strip_trailing_sep, path)
     # search the plugin path before the bzrlib installed dir
-    path.append(os.path.dirname(plugins.__file__))
-    plugins.__path__ = path
+    path.append(os.path.dirname(_mod_plugins.__file__))
+    _mod_plugins.__path__ = path
     return path
 
 
@@ -133,7 +134,7 @@
     # this function, and since it sets plugins.__path__, it should set it to
     # something that will be valid for Python to use (in case people try to
     # run "import bzrlib.plugins.PLUGINNAME" after calling this function).
-    plugins.__path__ = map(_strip_trailing_sep, dirs)
+    _mod_plugins.__path__ = map(_strip_trailing_sep, dirs)
     for d in dirs:
         if not d:
             continue
@@ -179,7 +180,7 @@
                     break
             else:
                 continue
-        if getattr(plugins, f, None):
+        if getattr(_mod_plugins, f, None):
             mutter('Plugin name %s already loaded', f)
         else:
             # mutter('add plugin name %s', f)
@@ -263,7 +264,7 @@
     
         if not plugin_name:
             continue
-        if getattr(plugins, plugin_name, None):
+        if getattr(_mod_plugins, plugin_name, None):
             mutter('Plugin name %s already loaded', plugin_name)
             continue
     
@@ -279,6 +280,18 @@
             log_exception_quietly()
 
 
+def plugins():
+    """Return a dictionary of the plugins.
+    
+    Each item in the dictionary is a PlugIn object.
+    """
+    result = {}
+    for name, plugin in _mod_plugins.__dict__.items():
+        if isinstance(plugin, types.ModuleType):
+            result[name] = PlugIn(name, plugin)
+    return result
+
+
 class PluginsHelpIndex(object):
     """A help index that returns help topics for plugins."""
 
@@ -345,3 +358,57 @@
     def get_help_topic(self):
         """Return the modules help topic - its __name__ after bzrlib.plugins.."""
         return self.module.__name__[len('bzrlib.plugins.'):]
+
+
+class PlugIn(object):
+    """The bzrlib representation of a plugin.
+
+    The PlugIn object provides a way to manipulate a given plugin module.
+    """
+
+    def __init__(self, name, module):
+        """Construct a plugin for module."""
+        self.name = name
+        self.module = module
+
+    def path(self):
+        """Get the path that this plugin was loaded from."""
+        if getattr(self.module, '__path__', None) is not None:
+            return os.path.abspath(self.module.__path__[0])
+        elif getattr(self.module, '__file__', None) is not None:
+            return os.path.abspath(self.module.__file__)
+        else:
+            return repr(self.module)
+
+    def __str__(self):
+        return "<%s.%s object at %s, name=%s, module=%s>" % (
+            self.__class__.__module__, self.__class__.__name__, id(self),
+            self.name, self.module)
+
+    __repr__ = __str__
+
+    def test_suite(self):
+        """Return the plugin's test suite."""
+        if getattr(self.module, 'test_suite', None) is not None:
+            return self.module.test_suite()
+        else:
+            return None
+
+    def version_info(self):
+        """Return the plugin's version_tuple or None if unknown."""
+        version_info = getattr(self.module, 'version_info', None)
+        if version_info is not None and len(version_info) == 3:
+            version_info = tuple(version_info) + ('final', 0)
+        return version_info
+    
+    def _get__version__(self):
+        version_info = self.version_info()
+        if version_info is None:
+            return "unknown"
+        if version_info[3] == 'final':
+            version_string = '%d.%d.%d' % version_info[:3]
+        else:
+            version_string = '%d.%d.%d%s%d' % version_info
+        return version_string
+
+    __version__ = property(_get__version__)

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2007-08-28 07:52:00 +0000
+++ b/bzrlib/tests/__init__.py	2007-08-29 01:16:53 +0000
@@ -2496,22 +2496,22 @@
         except ValueError, e:
             print '**failed to get doctest for: %s\n%s' %(m,e)
             raise
-    for name, plugin in bzrlib.plugin.all_plugins().items():
-        if getattr(plugin, 'test_suite', None) is not None:
-            default_encoding = sys.getdefaultencoding()
-            try:
-                plugin_suite = plugin.test_suite()
-            except ImportError, e:
-                bzrlib.trace.warning(
-                    'Unable to test plugin "%s": %s', name, e)
-            else:
+    default_encoding = sys.getdefaultencoding()
+    for name, plugin in bzrlib.plugin.plugins().items():
+        try:
+            plugin_suite = plugin.test_suite()
+        except ImportError, e:
+            bzrlib.trace.warning(
+                'Unable to test plugin "%s": %s', name, e)
+        else:
+            if plugin_suite is not None:
                 suite.addTest(plugin_suite)
-            if default_encoding != sys.getdefaultencoding():
-                bzrlib.trace.warning(
-                    'Plugin "%s" tried to reset default encoding to: %s', name,
-                    sys.getdefaultencoding())
-                reload(sys)
-                sys.setdefaultencoding(default_encoding)
+        if default_encoding != sys.getdefaultencoding():
+            bzrlib.trace.warning(
+                'Plugin "%s" tried to reset default encoding to: %s', name,
+                sys.getdefaultencoding())
+            reload(sys)
+            sys.setdefaultencoding(default_encoding)
     return suite
 
 

=== modified file 'bzrlib/tests/test_plugins.py'
--- a/bzrlib/tests/test_plugins.py	2007-08-28 04:34:10 +0000
+++ b/bzrlib/tests/test_plugins.py	2007-08-29 01:16:53 +0000
@@ -30,6 +30,7 @@
 import bzrlib.plugins
 import bzrlib.commands
 import bzrlib.help
+from bzrlib.symbol_versioning import zero_ninetyone
 from bzrlib.tests import TestCase, TestCaseInTempDir
 from bzrlib.osutils import pathjoin, abspath
 
@@ -88,6 +89,8 @@
         finally:
             # remove the plugin 'plugin'
             del self.activeattributes[tempattribute]
+            if 'bzrlib.plugins.plugin' in sys.modules:
+                del sys.modules['bzrlib.plugins.plugin']
             if getattr(bzrlib.plugins, 'plugin', None):
                 del bzrlib.plugins.plugin
         self.failIf(getattr(bzrlib.plugins, 'plugin', None))
@@ -137,9 +140,12 @@
         finally:
             # remove the plugin 'plugin'
             del self.activeattributes[tempattribute]
-            if getattr(bzrlib.plugins, 'plugin', None):
-                del bzrlib.plugins.plugin
-        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
+            if getattr(bzrlib.plugins, 'pluginone', None):
+                del bzrlib.plugins.pluginone
+            if getattr(bzrlib.plugins, 'plugintwo', None):
+                del bzrlib.plugins.plugintwo
+        self.failIf(getattr(bzrlib.plugins, 'pluginone', None))
+        self.failIf(getattr(bzrlib.plugins, 'plugintwo', None))
 
     def test_plugins_can_load_from_directory_with_trailing_slash(self):
         # This test tests that a plugin can load from a directory when the
@@ -188,10 +194,11 @@
         print >> file('plugin.py', 'w'), ""
         try:
             bzrlib.plugin.load_from_path(['.'])
-            self.failUnless('plugin' in bzrlib.plugin.all_plugins())
+            all_plugins = self.applyDeprecated(zero_ninetyone,
+                bzrlib.plugin.all_plugins)
+            self.failUnless('plugin' in all_plugins)
             self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
-            self.assertEqual(bzrlib.plugin.all_plugins()['plugin'],
-                             bzrlib.plugins.plugin)
+            self.assertEqual(all_plugins['plugin'], bzrlib.plugins.plugin)
         finally:
             # remove the plugin 'plugin'
             if 'bzrlib.plugins.plugin' in sys.modules:
@@ -201,6 +208,85 @@
         self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
 
+class TestPlugins(TestCaseInTempDir):
+
+    def setup_plugin(self, source=""):
+        # This test tests a new plugin appears in bzrlib.plugin.plugins().
+        # check the plugin is not loaded already
+        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
+        # write a plugin that _cannot_ fail to load.
+        print >> file('plugin.py', 'w'), source
+        self.addCleanup(self.teardown_plugin)
+        bzrlib.plugin.load_from_path(['.'])
+    
+    def teardown_plugin(self):
+        # remove the plugin 'plugin'
+        if 'bzrlib.plugins.plugin' in sys.modules:
+            del sys.modules['bzrlib.plugins.plugin']
+        if getattr(bzrlib.plugins, 'plugin', None):
+            del bzrlib.plugins.plugin
+        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
+
+    def test_plugin_appears_in_plugins(self):
+        self.setup_plugin()
+        self.failUnless('plugin' in bzrlib.plugin.plugins())
+        self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
+        plugins = bzrlib.plugin.plugins()
+        plugin = plugins['plugin']
+        self.assertIsInstance(plugin, bzrlib.plugin.PlugIn)
+        self.assertEqual(bzrlib.plugins.plugin, plugin.module)
+
+    def test_trivial_plugin_get_path(self):
+        self.setup_plugin()
+        plugins = bzrlib.plugin.plugins()
+        plugin = plugins['plugin']
+        plugin_path = self.test_dir + '/plugin.py'
+        self.assertEqual(plugin_path, plugin.path())
+
+    def test_no_test_suite_gives_None_for_test_suite(self):
+        self.setup_plugin()
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual(None, plugin.test_suite())
+
+    def test_test_suite_gives_test_suite_result(self):
+        source = """def test_suite(): return 'foo'"""
+        self.setup_plugin(source)
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual('foo', plugin.test_suite())
+
+    def test_no_version_info(self):
+        self.setup_plugin()
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual(None, plugin.version_info())
+
+    def test_with_version_info(self):
+        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual((1, 2, 3, 'dev', 4), plugin.version_info())
+
+    def test_short_version_info_gets_padded(self):
+        # the gtk plugin has version_info = (1,2,3) rather than the 5-tuple.
+        # so we adapt it
+        self.setup_plugin("version_info = (1, 2, 3)")
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual((1, 2, 3, 'final', 0), plugin.version_info())
+
+    def test_no_version_info___version__(self):
+        self.setup_plugin()
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual("unknown", plugin.__version__)
+
+    def test___version__with_version_info(self):
+        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual("1.2.3dev4", plugin.__version__)
+
+    def test_final__version__with_version_info(self):
+        self.setup_plugin("version_info = (1, 2, 3, 'final', 4)")
+        plugin = bzrlib.plugin.plugins()['plugin']
+        self.assertEqual("1.2.3", plugin.__version__)
+
+
 class TestPluginHelp(TestCaseInTempDir):
 
     def split_help_commands(self):



More information about the bazaar-commits mailing list