32: Added Plugin and Proxy base classes in plugable module, along with to_cli() and from_cli() functions; added correspending unit tests

This commit is contained in:
Jason Gerard DeRose 2008-07-31 22:36:15 +00:00
parent d7569a84b9
commit a131ebf724
2 changed files with 131 additions and 0 deletions

View File

@ -21,10 +21,94 @@
Utility classes for registering plugins, base classe for writing plugins. Utility classes for registering plugins, base classe for writing plugins.
""" """
import inspect import inspect
import errors import errors
def to_cli(name):
assert isinstance(name, basestring)
return name.replace('__', '.').replace('_', '-')
def from_cli(cli_name):
assert isinstance(cli_name, basestring)
return cli_name.replace('-', '_').replace('.', '__')
class Plugin(object):
"""
Base class for all plugins.
"""
def __get_name(self):
"""
Returns the class name of this instance.
"""
return self.__class__.__name__
name = property(__get_name)
def __repr__(self):
"""
Returns a valid Python expression that could create this plugin
instance given the appropriate environment.
"""
return '%s.%s()' % (
self.__class__.__module__,
self.__class__.__name__
)
class Proxy(object):
"""
Used to only export certain attributes into the dynamic API.
Subclasses must list names of attributes to be proxied in the __slots__
class attribute.
"""
__slots__ = (
'__obj',
'name',
'cli_name',
)
def __init__(self, obj, proxy_name=None):
"""
Proxy attributes on `obj`.
"""
if proxy_name is None:
proxy_name = obj.name
assert isinstance(proxy_name, str)
object.__setattr__(self, '_Proxy__obj', obj)
object.__setattr__(self, 'name', proxy_name)
object.__setattr__(self, 'cli_name', to_cli(proxy_name))
for name in self.__slots__:
object.__setattr__(self, name, getattr(obj, name))
def __setattr__(self, name, value):
"""
Proxy instances are read-only. This raises an AttributeError
anytime an attempt is made to set an attribute.
"""
raise AttributeError('cannot set %s.%s' %
(self.__class__.__name__, name)
)
def __delattr__(self, name):
"""
Proxy instances are read-only. This raises an AttributeError
anytime an attempt is made to delete an attribute.
"""
raise AttributeError('cannot del %s.%s' %
(self.__class__.__name__, name)
)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.__obj)
def __str__(self):
return self.cli_name
class Registrar(object): class Registrar(object):
def __init__(self, *allowed): def __init__(self, *allowed):

View File

@ -24,6 +24,53 @@ Unit tests for `ipalib.plugable` module.
from ipalib import plugable, errors from ipalib import plugable, errors
def test_to_cli():
f = plugable.to_cli
assert f('initialize') == 'initialize'
assert f('find_everything') == 'find-everything'
assert f('user__add') == 'user.add'
assert f('meta_service__do_something') == 'meta-service.do-something'
def test_from_cli():
f = plugable.from_cli
assert f('initialize') == 'initialize'
assert f('find-everything') == 'find_everything'
assert f('user.add') == 'user__add'
assert f('meta-service.do-something') == 'meta_service__do_something'
def test_Plugin():
p = plugable.Plugin()
assert p.name == 'Plugin'
assert repr(p) == '%s.Plugin()' % plugable.__name__
class some_plugin(plugable.Plugin):
pass
p = some_plugin()
assert p.name == 'some_plugin'
assert repr(p) == '%s.some_plugin()' % __name__
def test_Proxy():
class CommandProxy(plugable.Proxy):
__slots__ = (
'get_label',
'__call__',
)
class Command(plugable.Plugin):
def get_label(self):
return 'Add User'
def __call__(self, *argv, **kw):
return (argv, kw)
i = Command()
p = CommandProxy(i, 'hello')
assert '__dict__' not in dir(p)
#assert repr(p) == 'CommandProxy(%s.Command())' % __name__
def test_Registrar(): def test_Registrar():
class Base1(object): class Base1(object):
pass pass