For the UI work I needed to stop wrapping commands in PluginProxy so I
can check if a command is an instance of crud.Create, crud.Retrieve, and
so on.  Plus, PluginProxy just wasn't as good an idea as I first
thought.  ;)

This patch removes the PluginProxy class and all it's uses.


>From c4b8d2c22ff3b4f75f480ba301d5337320050faf Mon Sep 17 00:00:00 2001
From: Jason Gerard DeRose <jder...@redhat.com>
Date: Tue, 4 Aug 2009 02:41:11 -0600
Subject: [PATCH] Removed PluginProxy and all its uses

---
 ipalib/__init__.py                 |    4 +-
 ipalib/base.py                     |    8 +-
 ipalib/cli.py                      |   15 ++--
 ipalib/frontend.py                 |   12 ++--
 ipalib/plugable.py                 |  117 +-------------------------
 tests/test_ipalib/test_frontend.py |    2 +-
 tests/test_ipalib/test_plugable.py |  164 +++---------------------------------
 7 files changed, 35 insertions(+), 287 deletions(-)

diff --git a/ipalib/__init__.py b/ipalib/__init__.py
index 4ad58d6..b21c303 100644
--- a/ipalib/__init__.py
+++ b/ipalib/__init__.py
@@ -239,9 +239,7 @@ plugin you implement.
 
 Backend plugins are much more free-form than command plugins.  Aside from a
 few reserved attribute names, you can define arbitrary public methods on your
-backend plugin (in contrast, frontend plugins get wrapped in a
-`plugable.PluginProxy`, which allow access to only specific attributes on the
-frontend plugin).
+backend plugin.
 
 Here is a simple example:
 
diff --git a/ipalib/base.py b/ipalib/base.py
index e0951e4..38b1e8f 100644
--- a/ipalib/base.py
+++ b/ipalib/base.py
@@ -382,7 +382,7 @@ class NameSpace(ReadOnly):
     examples, see the `plugable.API` and the `frontend.Command` classes.
     """
 
-    def __init__(self, members, sort=True):
+    def __init__(self, members, sort=True, name_attr='name'):
         """
         :param members: An iterable providing the members.
         :param sort: Whether to sort the members by member name.
@@ -394,14 +394,14 @@ class NameSpace(ReadOnly):
         self.__sort = sort
         if sort:
             self.__members = tuple(
-                sorted(members, key=lambda m: m.name)
+                sorted(members, key=lambda m: getattr(m, name_attr))
             )
         else:
             self.__members = tuple(members)
-        self.__names = tuple(m.name for m in self.__members)
+        self.__names = tuple(getattr(m, name_attr) for m in self.__members)
         self.__map = dict()
         for member in self.__members:
-            name = check_name(member.name)
+            name = check_name(getattr(member,  name_attr))
             if name in self.__map:
                 raise AttributeError(OVERRIDE_ERROR %
                     (self.__class__.__name__, name, self.__map[name], member)
diff --git a/ipalib/cli.py b/ipalib/cli.py
index 3258556..5f78223 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -491,12 +491,15 @@ class help(frontend.Command):
 
     _PLUGIN_BASE_MODULE = 'ipalib.plugins'
 
-    def _get_command_module(self, cmd_plugin_proxy):
+    def _get_command_module(self, module):
         """
-        Return bare module name where command represented by PluginProxy
-        instance is defined. Return None if command isn't defined in
-        a plugin module (we consider these commands to be builtins).
+        Return last part of ``module`` name, or ``None`` if module is this file.
+
+        For example:
         """
+        if module == __name__:
+            return
+        return module.split('.')[-1]
         # get representation in the form of 'base_module.bare_module.command()'
         r = repr(cmd_plugin_proxy)
         # skip base module part and the following dot
@@ -517,7 +520,7 @@ class help(frontend.Command):
 
         # build help topics
         for c in self.Command():
-            topic = self._get_command_module(c)
+            topic = self._get_command_module(c.module)
             if topic:
                 self._topics.setdefault(topic, [0]).append(c)
                 # compute maximum length of command in topic
@@ -528,7 +531,7 @@ class help(frontend.Command):
 
         # compute maximum topic length
         self._mtl = max(
-            len(s) for s in (self._topics.keys() + self._builtins)
+            len(s) for s in (self._topics.keys() + [c.name for c in self._builtins])
         )
 
         super(help, self).finalize()
diff --git a/ipalib/frontend.py b/ipalib/frontend.py
index 2a5c531..5ee7038 100644
--- a/ipalib/frontend.py
+++ b/ipalib/frontend.py
@@ -352,7 +352,7 @@ class Command(HasParam):
     >>> list(api.Command)
     ['my_command']
     >>> api.Command.my_command # doctest:+ELLIPSIS
-    PluginProxy(Command, ...my_command())
+    ipalib.frontend.my_command()
     """
 
     __public__ = frozenset((
@@ -752,10 +752,10 @@ class Object(HasParam):
     def set_api(self, api):
         super(Object, self).set_api(api)
         self.methods = NameSpace(
-            self.__get_attrs('Method'), sort=False
+            self.__get_attrs('Method'), sort=False, name_attr='attr_name'
         )
         self.properties = NameSpace(
-            self.__get_attrs('Property'), sort=False
+            self.__get_attrs('Property'), sort=False, name_attr='attr_name'
         )
         self._create_param_namespace('params')
         pkeys = filter(lambda p: p.primary_key, self.params())
@@ -798,9 +798,9 @@ class Object(HasParam):
             return
         namespace = self.api[name]
         assert type(namespace) is NameSpace
-        for proxy in namespace(): # Equivalent to dict.itervalues()
-            if proxy.obj_name == self.name:
-                yield proxy.__clone__('attr_name')
+        for plugin in namespace(): # Equivalent to dict.itervalues()
+            if plugin.obj_name == self.name:
+                yield plugin
 
     def get_params(self):
         """
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index ba7ac71..d94ff75 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -308,118 +308,6 @@ class Plugin(ReadOnly):
         )
 
 
-class PluginProxy(SetProxy):
-    """
-    Allow access to only certain attributes on a `Plugin`.
-
-    Think of a proxy as an agreement that "I will have at most these
-    attributes". This is different from (although similar to) an interface,
-    which can be thought of as an agreement that "I will have at least these
-    attributes".
-    """
-
-    __slots__ = (
-        '__base',
-        '__target',
-        '__name_attr',
-        '__public__',
-        'name',
-        'doc',
-    )
-
-    def __init__(self, base, target, name_attr='name'):
-        """
-        :param base: A subclass of `Plugin`.
-        :param target: An instance ``base`` or a subclass of ``base``.
-        :param name_attr: The name of the attribute on ``target`` from which
-            to derive ``self.name``.
-        """
-        if not inspect.isclass(base):
-            raise TypeError(
-                '`base` must be a class, got %r' % base
-            )
-        if not isinstance(target, base):
-            raise ValueError(
-                '`target` must be an instance of `base`, got %r' % target
-            )
-        self.__base = base
-        self.__target = target
-        self.__name_attr = name_attr
-        if hasattr(type(target), '__public__'):
-            self.__public__ = type(target).__public__
-        else:
-            self.__public__ = base.__public__
-        self.name = getattr(target, name_attr)
-        self.doc = target.doc
-        assert type(self.__public__) is frozenset
-        super(PluginProxy, self).__init__(self.__public__)
-
-    def implements(self, arg):
-        """
-        Return True if plugin being proxied implements ``arg``.
-
-        This method simply calls the corresponding `Plugin.implements`
-        classmethod.
-
-        Unlike `Plugin.implements`, this is not a classmethod as a
-        `PluginProxy` can only implement anything as an instance.
-        """
-        return self.__base.implements(arg)
-
-    def __clone__(self, name_attr):
-        """
-        Return a `PluginProxy` instance similar to this one.
-
-        The new `PluginProxy` returned will be identical to this one except
-        the proxy name might be derived from a different attribute on the
-        target `Plugin`.  The same base and target will be used.
-        """
-        return self.__class__(self.__base, self.__target, name_attr)
-
-    def __getitem__(self, key):
-        """
-        Return attribute named ``key`` on target `Plugin`.
-
-        If this proxy allows access to an attribute named ``key``, that
-        attribute will be returned.  If access is not allowed,
-        KeyError will be raised.
-        """
-        if key in self.__public__:
-            return getattr(self.__target, key)
-        raise KeyError('no public attribute %s.%s' % (self.name, key))
-
-    def __getattr__(self, name):
-        """
-        Return attribute named ``name`` on target `Plugin`.
-
-        If this proxy allows access to an attribute named ``name``, that
-        attribute will be returned.  If access is not allowed,
-        AttributeError will be raised.
-        """
-        if name in self.__public__:
-            return getattr(self.__target, name)
-        raise AttributeError('no public attribute %s.%s' % (self.name, name))
-
-    def __call__(self, *args, **kw):
-        """
-        Call target `Plugin` and return its return value.
-
-        If `__call__` is not an attribute this proxy allows access to,
-        KeyError is raised.
-        """
-        return self['__call__'](*args, **kw)
-
-    def __repr__(self):
-        """
-        Return a Python expression that could create this instance.
-        """
-        return '%s(%s, %r)' % (
-            self.__class__.__name__,
-            self.__base.__name__,
-            self.__target,
-        )
-
-
 class Registrar(DictProxy):
     """
     Collects plugin classes as they are registered.
@@ -734,10 +622,7 @@ class API(DictProxy):
                 p = plugins[klass]
                 assert base not in p.bases
                 p.bases.append(base)
-                if base.__proxy__:
-                    yield PluginProxy(base, p.instance)
-                else:
-                    yield p.instance
+                yield p.instance
 
         for name in self.register:
             base = self.register[name]
diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py
index 170891e..385219d 100644
--- a/tests/test_ipalib/test_frontend.py
+++ b/tests/test_ipalib/test_frontend.py
@@ -666,7 +666,7 @@ class test_Object(ClassChecker):
                 assert attr is getattr(namespace, attr_name)
                 assert attr.obj_name == 'user'
                 assert attr.attr_name == attr_name
-                assert attr.name == attr_name
+                assert attr.name == '%s_%s' % ('user', attr_name)
 
         # Test params instance attribute
         o = self.cls()
diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py
index 6f0cc29..ec1ef3e 100644
--- a/tests/test_ipalib/test_plugable.py
+++ b/tests/test_ipalib/test_plugable.py
@@ -377,128 +377,6 @@ class test_Plugin(ClassChecker):
         assert e.argv == ('/bin/false',)
 
 
-class test_PluginProxy(ClassChecker):
-    """
-    Test the `ipalib.plugable.PluginProxy` class.
-    """
-    _cls = plugable.PluginProxy
-
-    def test_class(self):
-        """
-        Test the `ipalib.plugable.PluginProxy` class.
-        """
-        assert self.cls.__bases__ == (plugable.SetProxy,)
-
-    def test_proxy(self):
-        """
-        Test proxy behaviour of `ipalib.plugable.PluginProxy` instance.
-        """
-        # Setup:
-        class base(object):
-            __public__ = frozenset((
-                'public_0',
-                'public_1',
-                '__call__',
-            ))
-
-            def public_0(self):
-                return 'public_0'
-
-            def public_1(self):
-                return 'public_1'
-
-            def __call__(self, caller):
-                return 'ya called it, %s.' % caller
-
-            def private_0(self):
-                return 'private_0'
-
-            def private_1(self):
-                return 'private_1'
-
-        class plugin(base):
-            name = 'user_add'
-            attr_name = 'add'
-            doc = 'add a new user'
-
-        # Test that TypeError is raised when base is not a class:
-        raises(TypeError, self.cls, base(), None)
-
-        # Test that ValueError is raised when target is not instance of base:
-        raises(ValueError, self.cls, base, object())
-
-        # Test with correct arguments:
-        i = plugin()
-        p = self.cls(base, i)
-        assert read_only(p, 'name') is plugin.name
-        assert read_only(p, 'doc') == plugin.doc
-        assert list(p) == sorted(base.__public__)
-
-        # Test normal methods:
-        for n in xrange(2):
-            pub = 'public_%d' % n
-            priv = 'private_%d' % n
-            assert getattr(i, pub)() == pub
-            assert getattr(p, pub)() == pub
-            assert hasattr(p, pub)
-            assert getattr(i, priv)() == priv
-            assert not hasattr(p, priv)
-
-        # Test __call__:
-        value = 'ya called it, dude.'
-        assert i('dude') == value
-        assert p('dude') == value
-        assert callable(p)
-
-        # Test name_attr='name' kw arg
-        i = plugin()
-        p = self.cls(base, i, 'attr_name')
-        assert read_only(p, 'name') == 'add'
-
-    def test_implements(self):
-        """
-        Test the `ipalib.plugable.PluginProxy.implements` method.
-        """
-        class base(object):
-            __public__ = frozenset()
-            name = 'base'
-            doc = 'doc'
-            @classmethod
-            def implements(cls, arg):
-                return arg + 7
-
-        class sub(base):
-            @classmethod
-            def implements(cls, arg):
-                """
-                Defined to make sure base.implements() is called, not
-                target.implements()
-                """
-                return arg
-
-        o = sub()
-        p = self.cls(base, o)
-        assert p.implements(3) == 10
-
-    def test_clone(self):
-        """
-        Test the `ipalib.plugable.PluginProxy.__clone__` method.
-        """
-        class base(object):
-            __public__ = frozenset()
-        class sub(base):
-            name = 'some_name'
-            doc = 'doc'
-            label = 'another_name'
-
-        p = self.cls(base, sub())
-        assert read_only(p, 'name') == 'some_name'
-        c = p.__clone__('label')
-        assert isinstance(c, self.cls)
-        assert c is not p
-        assert read_only(c, 'name') == 'another_name'
-
-
 def test_Registrar():
     """
     Test the `ipalib.plugable.Registrar` class
@@ -682,50 +560,34 @@ class test_API(ClassChecker):
         assert api.isdone('bootstrap') is True
         assert api.isdone('finalize') is True
 
-        def get_base(b):
+        def get_base_name(b):
             return 'base%d' % b
 
-        def get_plugin(b, p):
+
+        def get_plugin_name(b, p):
             return 'base%d_plugin%d' % (b, p)
 
         for b in xrange(2):
-            base_name = get_base(b)
+            base_name = get_base_name(b)
+            base = locals()[base_name]
             ns = getattr(api, base_name)
             assert isinstance(ns, plugable.NameSpace)
             assert read_only(api, base_name) is ns
             assert len(ns) == 3
             for p in xrange(3):
-                plugin_name = get_plugin(b, p)
-                proxy = ns[plugin_name]
-                assert isinstance(proxy, plugable.PluginProxy)
-                assert proxy.name == plugin_name
-                assert read_only(ns, plugin_name) is proxy
-                assert read_only(proxy, 'method')(7) == 7 + b
+                plugin_name = get_plugin_name(b, p)
+                plugin = locals()[plugin_name]
+                inst = ns[plugin_name]
+                assert isinstance(inst, base)
+                assert isinstance(inst, plugin)
+                assert inst.name == plugin_name
+                assert read_only(ns, plugin_name) is inst
+                assert inst.method(7) == 7 + b
 
         # Test that calling finilize again raises AssertionError:
         e = raises(StandardError, api.finalize)
         assert str(e) == 'API.finalize() already called', str(e)
 
-        # Test with base class that doesn't request a proxy
-        class NoProxy(plugable.Plugin):
-            __proxy__ = False
-        api = plugable.API(NoProxy)
-        api.env.mode = 'unit_test'
-        class plugin0(NoProxy):
-            pass
-        api.register(plugin0)
-        class plugin1(NoProxy):
-            pass
-        api.register(plugin1)
-        api.finalize()
-        names = ['plugin0', 'plugin1']
-        assert list(api.NoProxy) == names
-        for name in names:
-            plugin = api.NoProxy[name]
-            assert getattr(api.NoProxy, name) is plugin
-            assert isinstance(plugin, plugable.Plugin)
-            assert not isinstance(plugin, plugable.PluginProxy)
-
     def test_bootstrap(self):
         """
         Test the `ipalib.plugable.API.bootstrap` method.
-- 
1.6.0.4

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to