mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
90: Renamed plugable.Abstract to ProxyTarget, which now subclasses from ReadOnly; updated unit tests
This commit is contained in:
parent
6f144fbaf0
commit
5a1223e943
@ -43,7 +43,11 @@ class ReadOnly(object):
|
|||||||
__locked = False
|
__locked = False
|
||||||
|
|
||||||
def __lock__(self):
|
def __lock__(self):
|
||||||
assert self.__locked is False
|
"""
|
||||||
|
Puts this instance into a read-only state, after which attempting to
|
||||||
|
set or delete an attribute will raise AttributeError.
|
||||||
|
"""
|
||||||
|
assert self.__locked is False, '__lock__() can only be called once'
|
||||||
self.__locked = True
|
self.__locked = True
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
def __setattr__(self, name, value):
|
||||||
@ -69,7 +73,7 @@ class ReadOnly(object):
|
|||||||
return object.__delattr__(self, name)
|
return object.__delattr__(self, name)
|
||||||
|
|
||||||
|
|
||||||
class Abstract(object):
|
class ProxyTarget(ReadOnly):
|
||||||
__public__ = frozenset()
|
__public__ = frozenset()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -86,6 +90,58 @@ class Abstract(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Proxy(ReadOnly):
|
||||||
|
__slots__ = (
|
||||||
|
'__base',
|
||||||
|
'__target',
|
||||||
|
'__name_attr',
|
||||||
|
'name',
|
||||||
|
'__public__',
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, base, target, name_attr='name'):
|
||||||
|
if not inspect.isclass(base):
|
||||||
|
raise TypeError('arg1 must be a class, got %r' % base)
|
||||||
|
if not isinstance(target, base):
|
||||||
|
raise ValueError('arg2 must be instance of arg1, got %r' % target)
|
||||||
|
self.__base = base
|
||||||
|
self.__target = target
|
||||||
|
self.__name_attr = name_attr
|
||||||
|
self.name = getattr(target, name_attr)
|
||||||
|
self.__public__ = base.__public__
|
||||||
|
assert type(self.__public__) is frozenset
|
||||||
|
check_identifier(self.name)
|
||||||
|
self.__lock__()
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
for name in sorted(self.__public__):
|
||||||
|
yield name
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key in self.__public__:
|
||||||
|
return getattr(self.__target, key)
|
||||||
|
raise KeyError('no proxy attribute %r' % key)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name in self.__public__:
|
||||||
|
return getattr(self.__target, name)
|
||||||
|
raise AttributeError('no proxy attribute %r' % name)
|
||||||
|
|
||||||
|
def __call__(self, *args, **kw):
|
||||||
|
return self['__call__'](*args, **kw)
|
||||||
|
|
||||||
|
def _clone(self, name_attr):
|
||||||
|
return self.__class__(self.__base, self.__target, name_attr)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%s, %r, %r)' % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.__base.__name__,
|
||||||
|
self.__target,
|
||||||
|
self.__name_attr,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Plugin(object):
|
class Plugin(object):
|
||||||
"""
|
"""
|
||||||
Base class for all plugins.
|
Base class for all plugins.
|
||||||
@ -132,57 +188,7 @@ class Plugin(object):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Proxy(ReadOnly):
|
|
||||||
__slots__ = (
|
|
||||||
'__base',
|
|
||||||
'__target',
|
|
||||||
'__name_attr',
|
|
||||||
'name',
|
|
||||||
'__public__',
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, base, target, name_attr='name'):
|
|
||||||
if not inspect.isclass(base):
|
|
||||||
raise TypeError('arg1 must be a class, got %r' % base)
|
|
||||||
if not isinstance(target, base):
|
|
||||||
raise ValueError('arg2 must be instance of arg1, got %r' % target)
|
|
||||||
self.__base = base
|
|
||||||
self.__target = target
|
|
||||||
self.__name_attr = name_attr
|
|
||||||
self.name = getattr(target, name_attr)
|
|
||||||
self.__public__ = base.__public__
|
|
||||||
assert type(self.__public__) is frozenset
|
|
||||||
check_identifier(self.name)
|
|
||||||
self.__lock__()
|
|
||||||
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
for name in sorted(self.__public__):
|
|
||||||
yield name
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
if key in self.__public__:
|
|
||||||
return getattr(self.__target, key)
|
|
||||||
raise KeyError('no proxy attribute %r' % key)
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if name in self.__public__:
|
|
||||||
return getattr(self.__target, name)
|
|
||||||
raise AttributeError('no proxy attribute %r' % name)
|
|
||||||
|
|
||||||
def __call__(self, *args, **kw):
|
|
||||||
return self['__call__'](*args, **kw)
|
|
||||||
|
|
||||||
def _clone(self, name_attr):
|
|
||||||
return self.__class__(self.__base, self.__target, name_attr)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return '%s(%s, %r, %r)' % (
|
|
||||||
self.__class__.__name__,
|
|
||||||
self.__base.__name__,
|
|
||||||
self.__target,
|
|
||||||
self.__name_attr,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class NameSpace(ReadOnly):
|
class NameSpace(ReadOnly):
|
||||||
|
@ -26,6 +26,33 @@ from tstutil import ClassChecker
|
|||||||
from ipalib import plugable, errors
|
from ipalib import plugable, errors
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_identifier():
|
||||||
|
"""
|
||||||
|
Test the plugable.valid_identifier function.
|
||||||
|
"""
|
||||||
|
f = plugable.check_identifier
|
||||||
|
okay = [
|
||||||
|
'user_add',
|
||||||
|
'stuff2junk',
|
||||||
|
'sixty9',
|
||||||
|
]
|
||||||
|
nope = [
|
||||||
|
'_user_add',
|
||||||
|
'__user_add',
|
||||||
|
'user_add_',
|
||||||
|
'user_add__',
|
||||||
|
'_user_add_',
|
||||||
|
'__user_add__',
|
||||||
|
'60nine',
|
||||||
|
]
|
||||||
|
for name in okay:
|
||||||
|
f(name)
|
||||||
|
for name in nope:
|
||||||
|
raises(errors.NameSpaceError, f, name)
|
||||||
|
for name in okay:
|
||||||
|
raises(errors.NameSpaceError, f, name.upper())
|
||||||
|
|
||||||
|
|
||||||
class test_ReadOnly(ClassChecker):
|
class test_ReadOnly(ClassChecker):
|
||||||
"""
|
"""
|
||||||
Test the plugable.ReadOnly class
|
Test the plugable.ReadOnly class
|
||||||
@ -34,6 +61,7 @@ class test_ReadOnly(ClassChecker):
|
|||||||
|
|
||||||
def test_class(self):
|
def test_class(self):
|
||||||
assert self.cls.__bases__ == (object,)
|
assert self.cls.__bases__ == (object,)
|
||||||
|
assert callable(self.cls.__lock__)
|
||||||
|
|
||||||
def test_when_unlocked(self):
|
def test_when_unlocked(self):
|
||||||
"""
|
"""
|
||||||
@ -73,79 +101,64 @@ class test_ReadOnly(ClassChecker):
|
|||||||
assert read_only(obj, 'an_attribute') == 'Hello world!'
|
assert read_only(obj, 'an_attribute') == 'Hello world!'
|
||||||
|
|
||||||
|
|
||||||
|
class test_ProxyTarget(ClassChecker):
|
||||||
|
"""
|
||||||
|
Test the plugable.ProxyTarget class.
|
||||||
|
"""
|
||||||
|
_cls = plugable.ProxyTarget
|
||||||
|
|
||||||
def test_valid_identifier():
|
def test_class(self):
|
||||||
f = plugable.check_identifier
|
assert self.cls.__bases__ == (plugable.ReadOnly,)
|
||||||
okay = [
|
assert self.cls.implements(frozenset())
|
||||||
'user_add',
|
|
||||||
'stuff2junk',
|
|
||||||
'sixty9',
|
|
||||||
]
|
|
||||||
nope = [
|
|
||||||
'_user_add',
|
|
||||||
'__user_add',
|
|
||||||
'user_add_',
|
|
||||||
'user_add__',
|
|
||||||
'_user_add_',
|
|
||||||
'__user_add__',
|
|
||||||
'60nine',
|
|
||||||
]
|
|
||||||
for name in okay:
|
|
||||||
f(name)
|
|
||||||
for name in nope:
|
|
||||||
raises(errors.NameSpaceError, f, name)
|
|
||||||
for name in okay:
|
|
||||||
raises(errors.NameSpaceError, f, name.upper())
|
|
||||||
|
|
||||||
|
def test_implements(self):
|
||||||
def test_Abstract():
|
"""
|
||||||
cls = plugable.Abstract
|
Test the implements() classmethod
|
||||||
|
"""
|
||||||
class example(cls):
|
class example(self.cls):
|
||||||
__public__ = frozenset((
|
__public__ = frozenset((
|
||||||
'some_method',
|
'some_method',
|
||||||
'some_property',
|
'some_property',
|
||||||
))
|
))
|
||||||
|
class superset(self.cls):
|
||||||
# Test using str:
|
|
||||||
assert example.implements('some_method')
|
|
||||||
assert not example.implements('another_method')
|
|
||||||
|
|
||||||
# Test using frozenset:
|
|
||||||
assert example.implements(frozenset(['some_method']))
|
|
||||||
assert not example.implements(
|
|
||||||
frozenset(['some_method', 'another_method'])
|
|
||||||
)
|
|
||||||
|
|
||||||
# Test using another object/class with __public__ frozenset:
|
|
||||||
assert example.implements(example)
|
|
||||||
assert example().implements(example)
|
|
||||||
assert example.implements(example())
|
|
||||||
assert example().implements(example())
|
|
||||||
|
|
||||||
class subset(cls):
|
|
||||||
__public__ = frozenset((
|
|
||||||
'some_property',
|
|
||||||
))
|
|
||||||
assert example.implements(subset)
|
|
||||||
assert not subset.implements(example)
|
|
||||||
|
|
||||||
class superset(cls):
|
|
||||||
__public__ = frozenset((
|
__public__ = frozenset((
|
||||||
'some_method',
|
'some_method',
|
||||||
'some_property',
|
'some_property',
|
||||||
'another_property',
|
'another_property',
|
||||||
))
|
))
|
||||||
assert not example.implements(superset)
|
class subset(self.cls):
|
||||||
assert superset.implements(example)
|
__public__ = frozenset((
|
||||||
|
'some_property',
|
||||||
|
))
|
||||||
class any_object(object):
|
class any_object(object):
|
||||||
__public__ = frozenset((
|
__public__ = frozenset((
|
||||||
'some_method',
|
'some_method',
|
||||||
'some_property',
|
'some_property',
|
||||||
))
|
))
|
||||||
assert example.implements(any_object)
|
|
||||||
assert example.implements(any_object())
|
for ex in (example, example()):
|
||||||
|
# Test using str:
|
||||||
|
assert ex.implements('some_method')
|
||||||
|
assert not ex.implements('another_method')
|
||||||
|
|
||||||
|
# Test using frozenset:
|
||||||
|
assert ex.implements(frozenset(['some_method']))
|
||||||
|
assert not ex.implements(
|
||||||
|
frozenset(['some_method', 'another_method'])
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test using another object/class with __public__ frozenset:
|
||||||
|
assert ex.implements(example)
|
||||||
|
assert ex.implements(example())
|
||||||
|
|
||||||
|
assert ex.implements(subset)
|
||||||
|
assert not subset.implements(ex)
|
||||||
|
|
||||||
|
assert not ex.implements(superset)
|
||||||
|
assert superset.implements(ex)
|
||||||
|
|
||||||
|
assert ex.implements(any_object)
|
||||||
|
assert ex.implements(any_object())
|
||||||
|
|
||||||
|
|
||||||
def test_Plugin():
|
def test_Plugin():
|
||||||
|
Loading…
Reference in New Issue
Block a user