85: Added ReadOnly._lock() method to make class easier to use; updated subclasses and unit tests

This commit is contained in:
Jason Gerard DeRose 2008-08-08 21:28:56 +00:00
parent 6dc60a18c7
commit 58a3b1d091
2 changed files with 35 additions and 26 deletions

View File

@ -118,25 +118,33 @@ class ReadOnly(object):
""" """
Base class for classes with read-only attributes. 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): def __setattr__(self, name, value):
""" """
This raises an AttributeError anytime an attempt is made to set an Raises an AttributeError if ReadOnly._lock() has already been called;
attribute. otherwise calls object.__setattr__()
""" """
raise AttributeError('read-only: cannot set %s.%s' % if self.__locked:
(self.__class__.__name__, name) raise AttributeError('read-only: cannot set %s.%s' %
) (self.__class__.__name__, name)
)
return object.__setattr__(self, name, value)
def __delattr__(self, name): def __delattr__(self, name):
""" """
This raises an AttributeError anytime an attempt is made to delete an Raises an AttributeError if ReadOnly._lock() has already been called;
attribute. otherwise calls object.__delattr__()
""" """
raise AttributeError('read-only: cannot del %s.%s' % if self.__locked:
(self.__class__.__name__, name) raise AttributeError('read-only: cannot del %s.%s' %
) (self.__class__.__name__, name)
)
return object.__delattr__(self, name)
class Proxy(ReadOnly): class Proxy(ReadOnly):
@ -153,17 +161,15 @@ class Proxy(ReadOnly):
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, '_Proxy__base', base) self.__base = base
object.__setattr__(self, '_Proxy__target', target) self.__target = target
object.__setattr__(self, '_Proxy__name_attr', name_attr) self.__name_attr = name_attr
object.__setattr__(self, '__public__', base.__public__) self.name = getattr(target, name_attr)
object.__setattr__(self, 'name', getattr(target, name_attr)) self.__public__ = base.__public__
# Check __public__
assert type(self.__public__) is frozenset assert type(self.__public__) is frozenset
# Check name
check_identifier(self.name) check_identifier(self.name)
self._lock()
def __iter__(self): def __iter__(self):
for name in sorted(self.__public__): for name in sorted(self.__public__):
@ -204,14 +210,15 @@ class NameSpace(ReadOnly):
""" """
NameSpace NameSpace
""" """
object.__setattr__(self, '_NameSpace__proxies', tuple(proxies)) self.__proxies = tuple(proxies)
object.__setattr__(self, '_NameSpace__d', dict()) self.__d = dict()
for proxy in self.__proxies: for proxy in self.__proxies:
assert isinstance(proxy, Proxy) assert isinstance(proxy, Proxy)
assert proxy.name not in self.__d assert proxy.name not in self.__d
self.__d[proxy.name] = proxy self.__d[proxy.name] = proxy
assert not hasattr(self, proxy.name) assert not hasattr(self, proxy.name)
object.__setattr__(self, proxy.name, proxy) setattr(self, proxy.name, proxy)
self._lock()
def __iter__(self): def __iter__(self):
""" """
@ -338,8 +345,8 @@ class Registrar(object):
class API(ReadOnly): class API(ReadOnly):
def __init__(self, *allowed): def __init__(self, *allowed):
keys = tuple(b.__name__ for b in allowed) keys = tuple(b.__name__ for b in allowed)
object.__setattr__(self, '_API__keys', keys) self.register = Registrar(*allowed)
object.__setattr__(self, 'register', Registrar(*allowed)) self._lock()
def __call__(self): def __call__(self):
""" """

View File

@ -139,6 +139,7 @@ def test_Plugin():
def test_ReadOnly(): def test_ReadOnly():
obj = plugable.ReadOnly() obj = plugable.ReadOnly()
obj._lock()
names = ['not_an_attribute', 'an_attribute'] names = ['not_an_attribute', 'an_attribute']
for name in names: for name in names:
no_set(obj, name) no_set(obj, name)
@ -146,7 +147,8 @@ def test_ReadOnly():
class some_ro_class(plugable.ReadOnly): class some_ro_class(plugable.ReadOnly):
def __init__(self): def __init__(self):
object.__setattr__(self, 'an_attribute', 'Hello world!') self.an_attribute = 'Hello world!'
self._lock()
obj = some_ro_class() obj = some_ro_class()
for name in names: for name in names:
no_set(obj, name) no_set(obj, name)