incubator-allura-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tvansteenbu...@apache.org
Subject [32/45] git commit: [#6830] New entry point handling for allura tools
Date Fri, 13 Dec 2013 05:08:18 GMT
[#6830] New entry point handling for allura tools

New logic allows multiple EPs with the same name in the [allura] (tools)
section, as long as one of the EPs is a subclass of the other(s), in
which case the subclass will be the EP that is used, and the others with
the same name ignored.

Signed-off-by: Tim Van Steenburgh <tvansteenburgh@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/26209f4c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/26209f4c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/26209f4c

Branch: refs/heads/tv/6942
Commit: 26209f4ca9d992bef3ab202c95752851a8e6bc41
Parents: 3dc1bd6
Author: Tim Van Steenburgh <tvansteenburgh@gmail.com>
Authored: Mon Dec 9 22:03:43 2013 +0000
Committer: Cory Johns <admin1@users.sf.net>
Committed: Thu Dec 12 17:55:08 2013 +0000

----------------------------------------------------------------------
 Allura/allura/lib/helpers.py        | 44 +++++++++++++++++++++++++++-----
 Allura/allura/tests/test_helpers.py | 44 ++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/26209f4c/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index a987a3e..0b4e2dc 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -1000,13 +1000,43 @@ def plain2markdown(text, preserve_multiple_spaces=False, has_html_entities=False
 
 
 def iter_entry_points(group, *a, **kw):
-    '''
-    yield entry points that have not been disabled in the config
-    '''
-    disabled = aslist(tg.config.get('disable_entry_points.' + group), sep=',')
-    for ep in pkg_resources.iter_entry_points(group, *a, **kw):
-        if ep.name not in disabled:
-            yield ep
+    """Yields entry points that have not been disabled in the config.
+
+    If ``group`` is "allura" (Allura tool entry points), this function also
+    checks for multiple entry points with the same name. If there are
+    multiple entry points with the same name, and one of them is a subclass
+    of the other(s), it will be yielded, and the other entry points with that
+    name will be ignored. If a subclass is not found, an ImportError will be
+    raised.
+
+    This treatment of "allura" entry points allows tool authors to subclass
+    another tool while reusing the original entry point name.
+
+    """
+    def active_eps():
+        disabled = aslist(tg.config.get('disable_entry_points.' + group), sep=',')
+        return [ep for ep in pkg_resources.iter_entry_points(group, *a, **kw)
+                if ep.name not in disabled]
+    def unique_eps(entry_points):
+        by_name = defaultdict(list)
+        for ep in entry_points:
+            by_name[ep.name].append(ep)
+        for name, eps in by_name.iteritems():
+            ep_count = len(eps)
+            if ep_count == 1:
+                yield eps[0]
+            else:
+                yield subclass(eps)
+    def subclass(entry_points):
+        loaded = dict((ep, ep.load()) for ep in entry_points)
+        for ep, cls in loaded.iteritems():
+            others = loaded.values()[:]
+            others.remove(cls)
+            if all([issubclass(cls, other) for other in others]):
+                return ep
+        raise ImportError('Ambiguous [allura] entry points detected. ' +
+                'Multiple entry points with name "%s".' % entry_points[0].name)
+    return iter(unique_eps(active_eps()) if group == 'allura' else active_eps())
 
 
 # http://stackoverflow.com/a/1060330/79697

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/26209f4c/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index bdd3cea..e00231f 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -22,6 +22,7 @@ from os import path
 from datetime import datetime
 
 from mock import Mock, patch
+import tg
 from pylons import tmpl_context as c
 from nose.tools import eq_, assert_equals
 from IPython.testing.decorators import skipif, module_not_available
@@ -444,3 +445,46 @@ def test_login_overlay():
     with td.raises(HTTPUnauthorized):
         with h.login_overlay(exceptions=['foobar']):
             raise HTTPUnauthorized()
+
+class TestIterEntryPoints(TestCase):
+    def _make_ep(self, name, cls):
+        m = Mock()
+        m.name = name
+        m.load.return_value = cls
+        return m
+
+    @patch('allura.lib.helpers.pkg_resources')
+    @patch.dict(h.tg.config, {'disable_entry_points.allura': 'myapp'})
+    def test_disabled(self, pkg_resources):
+        pkg_resources.iter_entry_points.return_value = [
+                self._make_ep('myapp', object)]
+        self.assertEqual([], list(h.iter_entry_points('allura')))
+
+    @patch('allura.lib.helpers.pkg_resources')
+    def test_subclassed_ep(self, pkg_resources):
+        class App(object): pass
+        class BetterApp(App): pass
+
+        pkg_resources.iter_entry_points.return_value = [
+                self._make_ep('myapp', App),
+                self._make_ep('myapp', BetterApp)]
+
+        eps = list(h.iter_entry_points('allura'))
+        self.assertEqual(len(eps), 1)
+        self.assertEqual(BetterApp, eps[0].load())
+
+    @patch('allura.lib.helpers.pkg_resources')
+    def test_ambiguous_eps(self, pkg_resources):
+        class App(object): pass
+        class BetterApp(App): pass
+        class BestApp(object): pass
+
+        pkg_resources.iter_entry_points.return_value = [
+                self._make_ep('myapp', App),
+                self._make_ep('myapp', BetterApp),
+                self._make_ep('myapp', BestApp)]
+
+        self.assertRaisesRegexp(ImportError,
+                'Ambiguous \[allura\] entry points detected. '
+                'Multiple entry points with name "myapp".',
+                list, h.iter_entry_points('allura'))


Mime
View raw message