summaryrefslogtreecommitdiffstats
path: root/ipalib/base.py
diff options
context:
space:
mode:
authorJason Gerard DeRose <jderose@redhat.com>2008-07-19 00:56:09 +0000
committerJason Gerard DeRose <jderose@redhat.com>2008-07-19 00:56:09 +0000
commit5470a0d29a9131a5b95e6092df898ee579600e07 (patch)
treed4994cca3db7eb4aabff9535f141c03ea348c03d /ipalib/base.py
parent00f4da79a900ae2af1db82e4e697bd2552cdabc5 (diff)
downloadfreeipa-5470a0d29a9131a5b95e6092df898ee579600e07.zip
freeipa-5470a0d29a9131a5b95e6092df898ee579600e07.tar.gz
freeipa-5470a0d29a9131a5b95e6092df898ee579600e07.tar.xz
3: Finished NameSpace and cerresponding unit tests
Diffstat (limited to 'ipalib/base.py')
-rw-r--r--ipalib/base.py78
1 files changed, 71 insertions, 7 deletions
diff --git a/ipalib/base.py b/ipalib/base.py
index 70cfe56..eb84dd1 100644
--- a/ipalib/base.py
+++ b/ipalib/base.py
@@ -18,10 +18,10 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
-Base classes in for plug-in architecture and generative API.
+Base classes for plug-in architecture and generative API.
"""
-from exceptions import NameSpaceError
+from exceptions import SetAttributeError
class Command(object):
@@ -47,26 +47,90 @@ class Argument(object):
class NameSpace(object):
+ """
+ A read-only namespace of (key, value) pairs that can be accessed
+ both as instance attributes and as dictionary items. For example:
+
+ >>> ns = NameSpace(dict(my_message='Hello world!'))
+ >>> ns.my_message
+ 'Hello world!'
+ >>> ns['my_message']
+ 'Hello world!'
+
+ Keep in mind that Python doesn't offer true ready-only attributes. A
+ NameSpace is read-only in that it prevents programmers from
+ *accidentally* setting its attributes, but a motivated programmer can
+ still set them.
+
+ For example, setting an attribute the normal way will raise an exception:
+
+ >>> ns.my_message = 'some new value'
+ (raises ipalib.exceptions.SetAttributeError)
+
+ But a programmer could still set the attribute like this:
+
+ >>> ns.__dict__['my_message'] = 'some new value'
+
+ You should especially not implement a security feature that relies upon
+ NameSpace being strictly read-only.
+ """
+
+ __locked = False # Whether __setattr__ has been locked
+
def __init__(self, kw):
+ """
+ The single constructor argument `kw` is a dict of the (key, value)
+ pairs to be in this NameSpace instance.
+ """
assert isinstance(kw, dict)
self.__kw = dict(kw)
for (key, value) in self.__kw.items():
assert not key.startswith('_')
setattr(self, key, value)
self.__keys = sorted(self.__kw)
+ self.__locked = True
+
+ def __setattr__(self, name, value):
+ """
+ Raises an exception if trying to set an attribute after the
+ NameSpace has been locked; otherwise calls object.__setattr__().
+ """
+ if self.__locked:
+ raise SetAttributeError(name)
+ super(NameSpace, self).__setattr__(name, value)
def __getitem__(self, key):
+ """
+ Returns item from namespace named `key`.
+ """
return self.__kw[key]
- def __iter__(self):
- for key in self.__keys:
- yield key
-
-
+ def __hasitem__(self, key):
+ """
+ Returns True if namespace has an item named `key`.
+ """
+ return key in self.__kw
+ def __iter__(self):
+ """
+ Yields the names in this NameSpace in ascending order.
+ For example:
+ >>> ns = NameSpace(dict(attr_b='world', attr_a='hello'))
+ >>> list(ns)
+ ['attr_a', 'attr_b']
+ >>> [ns[k] for k in ns]
+ ['hello', 'world']
+ """
+ for key in self.__keys:
+ yield key
+ def __len__(self):
+ """
+ Returns number of items in this NameSpace.
+ """
+ return len(self.__keys)
class API(object):