summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
authorJason Gerard DeRose <jderose@redhat.com>2008-07-20 07:09:28 +0000
committerJason Gerard DeRose <jderose@redhat.com>2008-07-20 07:09:28 +0000
commit0cb26ef3ec68739a888f4295103210d301c2f9a8 (patch)
tree00b3b83408cf386a8d948f01918f2c20b5fd6c50 /ipalib
parentc2df39156979ea5a01901b97504c1de276364dfc (diff)
downloadfreeipa-0cb26ef3ec68739a888f4295103210d301c2f9a8.tar.gz
freeipa-0cb26ef3ec68739a888f4295103210d301c2f9a8.tar.xz
freeipa-0cb26ef3ec68739a888f4295103210d301c2f9a8.zip
15: Added ipalib.base2 module where I'm experimenting with a 3rd approach that is a hybrid of the first two: a decoupled late binding OO strategy
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/base2.py102
-rw-r--r--ipalib/exceptions.py4
-rw-r--r--ipalib/tests/test_base2.py142
3 files changed, 248 insertions, 0 deletions
diff --git a/ipalib/base2.py b/ipalib/base2.py
new file mode 100644
index 000000000..fa5536bd0
--- /dev/null
+++ b/ipalib/base2.py
@@ -0,0 +1,102 @@
+# Authors:
+# Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Base classes for plug-in architecture and generative API.
+"""
+
+import inspect
+import exceptions
+from base import NameSpace
+
+
+class Named(object):
+ def __get_name(self):
+ return self.__class__.__name__
+ name = property(__get_name)
+
+
+class WithObj(Named):
+ _obj = None
+ __obj = None
+
+ def __get_obj(self):
+ return self.__obj
+ def __set_obj(self, obj):
+ if self.__obj is not None:
+ raise exceptions.TwiceSetError(self.__class__.__name__, 'obj')
+ assert isinstance(obj, Named)
+ assert isinstance(self._obj, str)
+ assert obj.name == self._obj
+ self.__obj = obj
+ assert self.obj is obj
+ obj = property(__get_obj, __set_obj)
+
+
+class Command(WithObj):
+ pass
+
+class Property(WithObj):
+ pass
+
+class Object(Named):
+ pass
+
+
+class Registrar(object):
+ __object = None
+ __commands = None
+ __properties = None
+
+ def __init__(self):
+ self.__tmp_objects = {}
+ self.__tmp_commands = {}
+ self.__tmp_properties = {}
+
+ def __get_objects(self):
+ return self.__objects
+ objects = property(__get_objects)
+
+ def __get_commands(self):
+ return self.__commands
+ commands = property(__get_commands)
+
+ def __get_target(self, i):
+ if isinstance(i, Object):
+ return (self.__tmp_objects, i.name)
+ if isinstance(i, Command):
+ return (self.__tmp_commands, i.name)
+ assert isinstance(i, Property)
+
+
+ def register(self, cls):
+ assert inspect.isclass(cls)
+ assert issubclass(cls, Named)
+ i = cls()
+ (target, key) = self.__get_target(i)
+ target[key] = i
+
+ def finalize(self):
+ for cmd in self.__tmp_commands.values():
+ if cmd._obj is None:
+ continue
+ obj = self.__tmp_objects[cmd._obj]
+ cmd.obj = obj
+ self.__objects = NameSpace(self.__tmp_objects)
+ self.__commands = NameSpace(self.__tmp_commands)
diff --git a/ipalib/exceptions.py b/ipalib/exceptions.py
index 4584c1eea..76c7da8c2 100644
--- a/ipalib/exceptions.py
+++ b/ipalib/exceptions.py
@@ -63,3 +63,7 @@ class RegistrationError(IPAError):
class PrefixError(IPAError):
msg = 'class name %r must start with %r'
+
+
+class TwiceSetError(IPAError):
+ msg = '%s.%s cannot be set twice'
diff --git a/ipalib/tests/test_base2.py b/ipalib/tests/test_base2.py
new file mode 100644
index 000000000..cdf96bdb3
--- /dev/null
+++ b/ipalib/tests/test_base2.py
@@ -0,0 +1,142 @@
+# Authors:
+# Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Unit tests for `ipalib.base` module.
+"""
+
+from ipalib import base2 as base
+from ipalib import exceptions
+
+
+def read_only(obj, name):
+ """
+ Check that a given property is read-only.
+ Returns the value of the property.
+ """
+ assert isinstance(obj, object)
+ assert hasattr(obj, name)
+ raised = False
+ try:
+ setattr(obj, name, 'some new obj')
+ except AttributeError:
+ raised = True
+ assert raised
+ return getattr(obj, name)
+
+
+class ClassChecker(object):
+ cls = None # Override this is subclasses
+
+ def new(self, *args, **kw):
+ return self.cls(*args, **kw)
+
+ def args(self):
+ return []
+
+ def kw(self):
+ return {}
+
+ def std(self):
+ return self.new(*self.args(), **self.kw())
+
+
+
+def test_Named():
+ class named_class(base.Named):
+ pass
+
+ i = named_class()
+ assert i.name == 'named_class'
+
+
+def test_WithObj():
+ class some_object(base.Named):
+ pass
+
+ class another_object(base.Named):
+ pass
+
+ class some_command(base.WithObj):
+ _obj = 'some_object'
+
+ obj = some_object()
+ cmd = some_command()
+
+ # Test that it can be set:
+ assert cmd.obj is None
+ cmd.obj = obj
+ assert cmd.obj is obj
+
+ # Test that it cannot be set twice:
+ raised = False
+ try:
+ cmd.obj = obj
+ except exceptions.TwiceSetError:
+ raised = True
+ assert raised
+
+ # Test that it can't be set with the wrong name:
+ obj = another_object()
+ cmd = some_command()
+ raised = False
+ try:
+ cmd.obj = obj
+ except AssertionError:
+ raised = True
+ assert raised
+
+
+def test_Registar():
+ class adduser(base.Command):
+ _obj = 'user'
+ class moduser(base.Command):
+ _obj = 'user'
+ class deluser(base.Command):
+ _obj = 'user'
+ class finduser(base.Command):
+ _obj = 'user'
+ class kinit(base.Command):
+ pass
+ class user(base.Object):
+ pass
+ class group(base.Object):
+ pass
+
+ r = base.Registrar()
+ r.register(adduser)
+ r.register(moduser)
+ r.register(deluser)
+ r.register(finduser)
+ r.register(kinit)
+ r.register(user)
+ r.register(group)
+
+ r.finalize()
+ assert len(r.commands) == 5
+ assert len(r.objects) == 2
+
+ obj = r.objects.user
+ assert type(obj) is user
+ for name in ['adduser', 'moduser', 'deluser', 'finduser']:
+ cmd = r.commands[name]
+ assert type(cmd) is locals()[name]
+ assert cmd.obj is obj
+
+ assert r.commands.kinit.obj is None