summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipalib/plugable.py57
-rw-r--r--ipalib/tests/test_plugable.py4
2 files changed, 35 insertions, 26 deletions
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index ad3d5872b..e328f0c30 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -118,25 +118,33 @@ class ReadOnly(object):
"""
Base class for classes with read-only attributes.
"""
- __slots__ = tuple()
+ __locked = False
+
+ def _lock(self):
+ assert self.__locked is False
+ self.__locked = True
def __setattr__(self, name, value):
"""
- This raises an AttributeError anytime an attempt is made to set an
- attribute.
+ Raises an AttributeError if ReadOnly._lock() has already been called;
+ otherwise calls object.__setattr__()
"""
- raise AttributeError('read-only: cannot set %s.%s' %
- (self.__class__.__name__, name)
- )
+ if self.__locked:
+ raise AttributeError('read-only: cannot set %s.%s' %
+ (self.__class__.__name__, name)
+ )
+ return object.__setattr__(self, name, value)
def __delattr__(self, name):
"""
- This raises an AttributeError anytime an attempt is made to delete an
- attribute.
+ Raises an AttributeError if ReadOnly._lock() has already been called;
+ otherwise calls object.__delattr__()
"""
- raise AttributeError('read-only: cannot del %s.%s' %
- (self.__class__.__name__, name)
- )
+ if self.__locked:
+ raise AttributeError('read-only: cannot del %s.%s' %
+ (self.__class__.__name__, name)
+ )
+ return object.__delattr__(self, name)
class Proxy(ReadOnly):
@@ -153,17 +161,15 @@ class Proxy(ReadOnly):
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)
- object.__setattr__(self, '_Proxy__base', base)
- object.__setattr__(self, '_Proxy__target', target)
- object.__setattr__(self, '_Proxy__name_attr', name_attr)
- object.__setattr__(self, '__public__', base.__public__)
- object.__setattr__(self, 'name', getattr(target, name_attr))
-
- # Check __public__
+ 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 name
check_identifier(self.name)
+ self._lock()
+
def __iter__(self):
for name in sorted(self.__public__):
@@ -204,14 +210,15 @@ class NameSpace(ReadOnly):
"""
NameSpace
"""
- object.__setattr__(self, '_NameSpace__proxies', tuple(proxies))
- object.__setattr__(self, '_NameSpace__d', dict())
+ self.__proxies = tuple(proxies)
+ self.__d = dict()
for proxy in self.__proxies:
assert isinstance(proxy, Proxy)
assert proxy.name not in self.__d
self.__d[proxy.name] = proxy
assert not hasattr(self, proxy.name)
- object.__setattr__(self, proxy.name, proxy)
+ setattr(self, proxy.name, proxy)
+ self._lock()
def __iter__(self):
"""
@@ -338,8 +345,8 @@ class Registrar(object):
class API(ReadOnly):
def __init__(self, *allowed):
keys = tuple(b.__name__ for b in allowed)
- object.__setattr__(self, '_API__keys', keys)
- object.__setattr__(self, 'register', Registrar(*allowed))
+ self.register = Registrar(*allowed)
+ self._lock()
def __call__(self):
"""
diff --git a/ipalib/tests/test_plugable.py b/ipalib/tests/test_plugable.py
index ad1645f12..af6ee0c94 100644
--- a/ipalib/tests/test_plugable.py
+++ b/ipalib/tests/test_plugable.py
@@ -139,6 +139,7 @@ def test_Plugin():
def test_ReadOnly():
obj = plugable.ReadOnly()
+ obj._lock()
names = ['not_an_attribute', 'an_attribute']
for name in names:
no_set(obj, name)
@@ -146,7 +147,8 @@ def test_ReadOnly():
class some_ro_class(plugable.ReadOnly):
def __init__(self):
- object.__setattr__(self, 'an_attribute', 'Hello world!')
+ self.an_attribute = 'Hello world!'
+ self._lock()
obj = some_ro_class()
for name in names:
no_set(obj, name)