mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-24 08:00:02 -06:00
65: Finished simplified Proxy2 class; updated unit tests
This commit is contained in:
parent
0c7769473c
commit
f13f1226b4
@ -53,9 +53,6 @@ class SetError(IPAError):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RegistrationError(IPAError):
|
class RegistrationError(IPAError):
|
||||||
"""
|
"""
|
||||||
Base class for errors that occur during plugin registration.
|
Base class for errors that occur during plugin registration.
|
||||||
|
@ -25,29 +25,6 @@ import re
|
|||||||
import inspect
|
import inspect
|
||||||
import errors
|
import errors
|
||||||
|
|
||||||
EXPORT_FLAG = 'exported'
|
|
||||||
|
|
||||||
def export(obj):
|
|
||||||
"""
|
|
||||||
Decorator function to set the 'exported' flag to True.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
>>> @export
|
|
||||||
>>> def my_func():
|
|
||||||
>>> pass
|
|
||||||
>>> assert my_func.exported is True
|
|
||||||
"""
|
|
||||||
assert not hasattr(obj, EXPORT_FLAG)
|
|
||||||
setattr(obj, EXPORT_FLAG, True)
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def is_exported(obj):
|
|
||||||
"""
|
|
||||||
Returns True if `obj` as an 'exported' attribute that is True.
|
|
||||||
"""
|
|
||||||
return getattr(obj, EXPORT_FLAG, False) is True
|
|
||||||
|
|
||||||
|
|
||||||
def to_cli(name):
|
def to_cli(name):
|
||||||
"""
|
"""
|
||||||
@ -192,53 +169,42 @@ class Proxy(ReadOnly):
|
|||||||
|
|
||||||
|
|
||||||
class Proxy2(ReadOnly):
|
class Proxy2(ReadOnly):
|
||||||
def __init__(self, base, target):
|
__slots__ = (
|
||||||
|
'base',
|
||||||
|
'name',
|
||||||
|
'__target',
|
||||||
|
)
|
||||||
|
def __init__(self, base, target, name_attr='name'):
|
||||||
if not inspect.isclass(base):
|
if not inspect.isclass(base):
|
||||||
raise TypeError('arg1 must be a class, got %r' % base)
|
raise TypeError('arg1 must be a class, got %r' % base)
|
||||||
if not isinstance(target, base):
|
if not isinstance(target, base):
|
||||||
raise ValueError('arg2 must be instance of arg1, got %r' % target)
|
raise ValueError('arg2 must be instance of arg1, got %r' % target)
|
||||||
object.__setattr__(self, 'base', base)
|
object.__setattr__(self, 'base', base)
|
||||||
object.__setattr__(self, '_Proxy2__target', target)
|
object.__setattr__(self, '_Proxy2__target', target)
|
||||||
object.__setattr__(self, '_Proxy2__props', dict())
|
|
||||||
|
|
||||||
names = [] # The names of exported attributes
|
# Check base.public
|
||||||
# This matches implied property fget methods like '_get_user'
|
assert type(self.base.public) is frozenset
|
||||||
r = re.compile(r'^_get_([a-z][_a-z0-9]*[a-z0-9])$')
|
|
||||||
for name in dir(base):
|
|
||||||
match = r.match(name)
|
|
||||||
if name != '__call__' and name.startswith('_') and not match:
|
|
||||||
continue # Skip '_SomeClass__private', etc.
|
|
||||||
base_attr = getattr(base, name)
|
|
||||||
if is_exported(base_attr):
|
|
||||||
target_attr = getattr(target, name)
|
|
||||||
assert not hasattr(self, name), 'Cannot override %r' % name
|
|
||||||
object.__setattr__(self, name, target_attr)
|
|
||||||
names.append(name)
|
|
||||||
if match:
|
|
||||||
assert callable(target_attr), '%s must be callable' % name
|
|
||||||
key = match.group(1)
|
|
||||||
assert not hasattr(self, key), (
|
|
||||||
'%r cannot override %r' % (name, key)
|
|
||||||
)
|
|
||||||
self.__props[key] = target_attr
|
|
||||||
object.__setattr__(self, '_Proxy2__names', tuple(names))
|
|
||||||
|
|
||||||
def __call__(self, *args, **kw):
|
# Check name
|
||||||
return self.__target(*args, **kw)
|
object.__setattr__(self, 'name', getattr(target, name_attr))
|
||||||
|
check_identifier(self.name)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for name in self.__names:
|
for name in sorted(self.base.public):
|
||||||
yield name
|
yield name
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key in self.base.public:
|
||||||
|
return getattr(self.__target, key)
|
||||||
|
raise KeyError('no proxy attribute %r' % key)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name in self.__props:
|
if name in self.base.public:
|
||||||
return self.__props[name]()
|
return getattr(self.__target, name)
|
||||||
raise AttributeError(name)
|
raise AttributeError('no proxy attribute %r' % name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __call__(self, *args, **kw):
|
||||||
|
return self['__call__'](*args, **kw)
|
||||||
|
|
||||||
|
|
||||||
class NameSpace(ReadOnly):
|
class NameSpace(ReadOnly):
|
||||||
|
@ -170,23 +170,22 @@ def test_Proxy():
|
|||||||
|
|
||||||
def test_Proxy2():
|
def test_Proxy2():
|
||||||
cls = plugable.Proxy2
|
cls = plugable.Proxy2
|
||||||
export = plugable.export
|
|
||||||
assert issubclass(cls, plugable.ReadOnly)
|
assert issubclass(cls, plugable.ReadOnly)
|
||||||
|
|
||||||
# Setup:
|
# Setup:
|
||||||
class base(object):
|
class base(object):
|
||||||
@export
|
public = frozenset((
|
||||||
|
'public_0',
|
||||||
|
'public_1',
|
||||||
|
'__call__',
|
||||||
|
))
|
||||||
|
|
||||||
def public_0(self):
|
def public_0(self):
|
||||||
return 'public_0'
|
return 'public_0'
|
||||||
|
|
||||||
@export
|
|
||||||
def public_1(self):
|
def public_1(self):
|
||||||
return 'public_1'
|
return 'public_1'
|
||||||
|
|
||||||
@export
|
|
||||||
def _get_some_prop(self):
|
|
||||||
return 'ya got it'
|
|
||||||
|
|
||||||
def __call__(self, caller):
|
def __call__(self, caller):
|
||||||
return 'ya called it, %s.' % caller
|
return 'ya called it, %s.' % caller
|
||||||
|
|
||||||
@ -197,7 +196,8 @@ def test_Proxy2():
|
|||||||
return 'private_1'
|
return 'private_1'
|
||||||
|
|
||||||
class plugin(base):
|
class plugin(base):
|
||||||
pass
|
name = 'user_add'
|
||||||
|
attr_name = 'add'
|
||||||
|
|
||||||
# Test that TypeError is raised when base is not a class:
|
# Test that TypeError is raised when base is not a class:
|
||||||
raises(TypeError, cls, base(), None)
|
raises(TypeError, cls, base(), None)
|
||||||
@ -209,7 +209,8 @@ def test_Proxy2():
|
|||||||
i = plugin()
|
i = plugin()
|
||||||
p = cls(base, i)
|
p = cls(base, i)
|
||||||
assert read_only(p, 'base') is base
|
assert read_only(p, 'base') is base
|
||||||
assert list(p) == ['_get_some_prop', 'public_0', 'public_1']
|
assert read_only(p, 'name') is 'user_add'
|
||||||
|
assert list(p) == sorted(base.public)
|
||||||
|
|
||||||
# Test normal methods:
|
# Test normal methods:
|
||||||
for n in xrange(2):
|
for n in xrange(2):
|
||||||
@ -217,6 +218,7 @@ def test_Proxy2():
|
|||||||
priv = 'private_%d' % n
|
priv = 'private_%d' % n
|
||||||
assert getattr(i, pub)() == pub
|
assert getattr(i, pub)() == pub
|
||||||
assert getattr(p, pub)() == pub
|
assert getattr(p, pub)() == pub
|
||||||
|
assert hasattr(p, pub)
|
||||||
assert getattr(i, priv)() == priv
|
assert getattr(i, priv)() == priv
|
||||||
assert not hasattr(p, priv)
|
assert not hasattr(p, priv)
|
||||||
|
|
||||||
@ -224,14 +226,11 @@ def test_Proxy2():
|
|||||||
value = 'ya called it, dude.'
|
value = 'ya called it, dude.'
|
||||||
assert i('dude') == value
|
assert i('dude') == value
|
||||||
assert p('dude') == value
|
assert p('dude') == value
|
||||||
|
assert callable(p)
|
||||||
|
|
||||||
# Test implied property:
|
# Test name_attr='name' kw arg
|
||||||
fget = '_get_some_prop'
|
i = plugin()
|
||||||
name = 'some_prop'
|
p = cls(base, i)
|
||||||
value = 'ya got it'
|
|
||||||
assert getattr(i, fget)() == value
|
|
||||||
assert getattr(p, fget)() == value
|
|
||||||
assert getattr(p, name) == value
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user