From 293b31ac75cd4f72c5d4a62ffc82df83c70f564f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 6 Aug 2008 14:30:21 +0000 Subject: [PATCH] 60: Remeved depreciated base.py, crud.py; remeved corresponding test_base.py, test_crud.py --- ipalib/base.py | 499 -------------------------------------- ipalib/crud.py | 37 --- ipalib/tests/test_base.py | 424 -------------------------------- ipalib/tests/test_crud.py | 22 -- 4 files changed, 982 deletions(-) delete mode 100644 ipalib/base.py delete mode 100644 ipalib/crud.py delete mode 100644 ipalib/tests/test_base.py delete mode 100644 ipalib/tests/test_crud.py diff --git a/ipalib/base.py b/ipalib/base.py deleted file mode 100644 index ae9dfae49..000000000 --- a/ipalib/base.py +++ /dev/null @@ -1,499 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 re -import inspect -import errors - - -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 errors.SetError) - - 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, order=None): - """ - The `kw` argument is a dict of the (key, value) pairs to be in this - NameSpace instance. The optional `order` keyword argument specifies - the order of the keys in this namespace; if omitted, the default is - to sort the keys in ascending order. - """ - assert isinstance(kw, dict) - self.__kw = dict(kw) - for (key, value) in self.__kw.items(): - assert not key.startswith('_') - setattr(self, key, value) - if order is None: - self.__keys = sorted(self.__kw) - else: - self.__keys = list(order) - assert set(self.__keys) == set(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 errors.SetError(name) - super(NameSpace, self).__setattr__(name, value) - - def __getitem__(self, key): - """ - Returns item from namespace named `key`. - """ - return self.__kw[key] - - def __hasitem__(self, key): - """ - Returns True if namespace has an item named `key`. - """ - return bool(key in self.__kw) - - def __iter__(self): - """ - Yields the names in this NameSpace in ascending order, or in the - the order specified in `order` kw arg. - - 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 __call__(self): - """ - Iterates through the values in this NameSpace in the same order as - the keys. - """ - for key in self.__keys: - yield self.__kw[key] - - def __len__(self): - """ - Returns number of items in this NameSpace. - """ - return len(self.__keys) - - - -class Named(object): - __name = None - - def _get_name(self): - return self.__class__.__name__ - - def __get_loc(self): - cls = self.__class__ - return '%s.%s' % (cls.__module__, cls.__name__) - loc = property(__get_loc) - - def __get_name(self): - if self.__name is None: - self.__name = self._get_name() - return self.__name - name = property(__get_name) - - def __get_cli_name(self): - return self.name.replace('_', '-') - cli_name = property(__get_cli_name) - - -class AbstractCommand(object): - def __call__(self): - print 'You called %s.%s()' % ( - self.__class__.__module__, - self.__class__.__name__ - ) - - def get_doc(self, _): - """ - This should return a gettext translated summarary of the command. - - For example, if you were documenting the 'add-user' command, you're - method would look something like this. - - >>> def get_doc(self, _): - >>> return _('add new user') - """ - raise NotImplementedError('%s.%s.%s()' % ( - self.__class__.__module__, - self.__class__.__name__, - 'get_doc', - ) - ) - - -class Attribute(Named): - __locked = False - __obj = None - - def __init__(self): - m = re.match('^([a-z]+)__([a-z]+)$', self.__class__.__name__) - assert m - self.__obj_name = m.group(1) - self.__attr_name = m.group(2) - - def __get_obj(self): - return self.__obj - def __set_obj(self, obj): - if self.__obj is not None: - raise errors.TwiceSetError(self.__class__.__name__, 'obj') - assert isinstance(obj, Object) - self.__obj = obj - assert self.obj is obj - obj = property(__get_obj, __set_obj) - - def __get_obj_name(self): - return self.__obj_name - obj_name = property(__get_obj_name) - - def __get_attr_name(self): - return self.__attr_name - attr_name = property(__get_attr_name) - - -class Method(AbstractCommand, Attribute): - def _get_name(self): - return '%s_%s' % (self.attr_name, self.obj_name) - - -class Property(Attribute): - def _get_name(self): - return self.attr_name - - -class Command(AbstractCommand, Named): - pass - - -class Object(Named): - __methods = None - __properties = None - - def __get_methods(self): - return self.__methods - def __set_methods(self, methods): - if self.__methods is not None: - raise errors.TwiceSetError( - self.__class__.__name__, 'methods' - ) - assert type(methods) is NameSpace - self.__methods = methods - assert self.methods is methods - methods = property(__get_methods, __set_methods) - - def __get_properties(self): - return self.__properties - def __set_properties(self, properties): - if self.__properties is not None: - raise errors.TwiceSetError( - self.__class__.__name__, 'properties' - ) - assert type(properties) is NameSpace - self.__properties = properties - assert self.properties is properties - properties = property(__get_properties, __set_properties) - - - -class AttributeCollector(object): - def __init__(self): - self.__d = {} - - def __getitem__(self, key): - assert isinstance(key, str) - if key not in self.__d: - self.__d[key] = {} - return self.__d[key] - - def __iter__(self): - for key in self.__d: - yield key - - def add(self, i): - assert isinstance(i, Attribute) - self[i.obj_name][i.attr_name] = i - - def namespaces(self): - for key in self: - yield (key, NameSpace(self[key])) - - -class Collector(object): - def __init__(self): - self.__d = {} - - def __get_d(self): - return dict(self.__d) - d = property(__get_d) - - def __iter__(self): - for key in self.__d: - yield key - - def add(self, i): - assert isinstance(i, Named) - self.__d[i.name] = i - - def ns(self): - return NameSpace(self.__d) - - -class Proxy(object): - def __init__(self, d): - self.__d = d - - def __getattr__(self, name): - if name not in self.__d: - raise AttributeError(name) - return self.__d[name] - - - -class Registrar(object): - __allowed = ( - Command, - Object, - Method, - Property, - ) - - def __init__(self, d=None): - if d is None: - self.__d = {} - else: - assert isinstance(d, dict) - assert d == {} - self.__d = d - for base in self.__allowed: - assert inspect.isclass(base) - assert base.__name__ not in self.__d - sub_d = {} - self.__d[base.__name__] = sub_d - setattr(self, base.__name__, Proxy(sub_d)) - - def __iter__(self): - for key in self.__d: - yield key - - def __getitem__(self, key): - return dict(self.__d[key]) - - def items(self): - for key in self: - yield (key, self[key]) - - def __findbase(self, cls): - if not inspect.isclass(cls): - raise errors.RegistrationError('not a class', cls) - for base in self.__allowed: - if issubclass(cls, base): - return base - raise errors.RegistrationError( - 'not subclass of an allowed base', - cls, - ) - - def __call__(self, cls): - base = self.__findbase(cls) - ns = self.__d[base.__name__] - assert cls.__name__ not in ns - ns[cls.__name__] = cls - - - def get_instances(self, base_name): - for cls in self[base_name].values(): - yield cls() - - def get_attrs(self, base_name): - d = {} - for i in self.get_instances(base_name): - if i.obj_name not in d: - d[i.obj_name] = [] - d[i.obj_name].append(i) - return d - - - - - - -class RegistrarOld(object): - - - def __init__(self): - self.__tmp_commands = Collector() - self.__tmp_objects = Collector() - self.__tmp_methods = AttributeCollector() - self.__tmp_properties = AttributeCollector() - - 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, Command): - return self.__tmp_commands - if isinstance(i, Object): - return self.__tmp_objects - if isinstance(i, Method): - return self.__tmp_methods - assert isinstance(i, Property) - return self.__tmp_properties - - - def register(self, cls): - assert inspect.isclass(cls) - assert issubclass(cls, Named) - i = cls() - self.__get_target(i).add(i) - - - def finalize(self): - self.__objects = self.__tmp_objects.ns() - for (key, ns) in self.__tmp_methods.namespaces(): - self.__objects[key].methods = ns - for (key, ns) in self.__tmp_properties.namespaces(): - self.__objects[key].properties = ns - commands = self.__tmp_commands.d - for obj in self.__objects(): - assert isinstance(obj, Object) - if obj.methods is None: - obj.methods = NameSpace({}) - if obj.properties is None: - obj.properties = NameSpace({}) - for m in obj.methods(): - m.obj = obj - assert m.name not in commands - commands[m.name] = m - for p in obj.properties(): - p.obj = obj - self.__commands = NameSpace(commands) - - - -class API(object): - __max_cmd_len = None - __objects = None - __commands = None - - def __init__(self, registrar): - assert isinstance(registrar, Registrar) - self.__r = registrar - - def __get_objects(self): - return self.__objects - objects = property(__get_objects) - - def __get_commands(self): - return self.__commands - commands = property(__get_commands) - - def __get_max_cmd_len(self): - if self.__max_cmd_len is None: - if self.commands is None: - return None - self.__max_cmd_len = max(len(n) for n in self.commands) - return self.__max_cmd_len - max_cmd_len = property(__get_max_cmd_len) - - def __items(self, base, name): - for cls in self.__r[base].values(): - i = cls() - yield (getattr(i, name), i) - - def __namespace(self, base, name): - return NameSpace(dict(self.__items(base, name))) - - - - def finalize(self): - self.__objects = self.__namespace('Object', 'name') - - m = {} - for obj in self.__objects(): - if obj.name not in m: - m[obj.name] = {} - - for cls in self.__r['Method'].values(): - meth = cls() - assert meth.obj_name in m - - return - - for (key, ns) in self.__tmp_methods.namespaces(): - self.__objects[key].methods = ns - for (key, ns) in self.__tmp_properties.namespaces(): - self.__objects[key].properties = ns - commands = self.__tmp_commands.d - for obj in self.__objects(): - assert isinstance(obj, Object) - if obj.methods is None: - obj.methods = NameSpace({}) - if obj.properties is None: - obj.properties = NameSpace({}) - for m in obj.methods(): - m.obj = obj - assert m.name not in commands - commands[m.name] = m - for p in obj.properties(): - p.obj = obj - self.__commands = NameSpace(commands) diff --git a/ipalib/crud.py b/ipalib/crud.py deleted file mode 100644 index b61239d20..000000000 --- a/ipalib/crud.py +++ /dev/null @@ -1,37 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 objects with CRUD functionality. -""" - -import base - - -class Add(base.Method): - pass - -class Del(base.Method): - pass - -class Mod(base.Method): - pass - -class Find(base.Method): - pass diff --git a/ipalib/tests/test_base.py b/ipalib/tests/test_base.py deleted file mode 100644 index da9de7a03..000000000 --- a/ipalib/tests/test_base.py +++ /dev/null @@ -1,424 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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 base, errors, crud - - -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()) - - -class test_NameSpace: - """ - Unit tests for `NameSpace` class. - """ - - def ns(self, kw): - """ - Returns a new NameSpace instance. - """ - return base.NameSpace(kw) - - def kw(self): - """ - Returns standard test kw dict suitable for passing to - NameSpace.__init__(). - """ - return dict( - attr_a='Hello', - attr_b='all', - attr_c='yall!', - ) - - def std(self): - """ - Returns standard (kw, ns) tuple. - """ - kw = self.kw() - ns = self.ns(kw) - return (kw, ns) - - def test_public(self): - """ - Tests that a NameSpace instance created with empty dict has no public - attributes (that would then conflict with names we want to assign to - the NameSpace). Also tests that a NameSpace instance created with a - non-empty dict has no unexpected public methods. - """ - ns = self.ns({}) - assert list(ns) == [] - assert len(ns) == 0 - for name in dir(ns): - assert name.startswith('__') or name.startswith('_NameSpace__') - (kw, ns) = self.std() - keys = set(kw) - for name in dir(ns): - assert ( - name.startswith('__') or - name.startswith('_NameSpace__') or - name in keys - ) - - def test_dict_vs_attr(self): - """ - Tests that NameSpace.__getitem__() and NameSpace.__getattr__() return - the same values. - """ - (kw, ns) = self.std() - assert len(kw) > 0 - assert len(kw) == len(list(ns)) - for (key, val) in kw.items(): - assert ns[key] is val - assert getattr(ns, key) is val - - def test_setattr(self): - """ - Tests that attributes cannot be set on NameSpace instance. - """ - (kw, ns) = self.std() - value = 'new value' - for key in kw: - raised = False - try: - setattr(ns, key, value) - except errors.SetError: - raised = True - assert raised - assert getattr(ns, key, None) != value - assert ns[key] != value - - def test_setitem(self): - """ - Tests that attributes cannot be set via NameSpace dict interface. - """ - (kw, ns) = self.std() - value = 'new value' - for key in kw: - raised = False - try: - ns[key] = value - except TypeError: - raised = True - assert raised - assert getattr(ns, key, None) != value - assert ns[key] != value - - def test_hasitem(self): - """ - Test __hasitem__() membership method. - """ - (kw, ns) = self.std() - nope = [ - 'attr_d', - 'attr_e', - 'whatever', - ] - for key in kw: - assert key in ns - for key in nope: - assert key not in kw - assert key not in ns - - def test_iter(self): - """ - Tests that __iter__() method returns sorted list of attribute names. - """ - (kw, ns) = self.std() - assert list(ns) == sorted(kw) - assert [ns[k] for k in ns] == ['Hello', 'all', 'yall!'] - - def test_len(self): - """ - Test __len__() method. - """ - (kw, ns) = self.std() - assert len(kw) == len(ns) == 3 - - -def test_Named(): - class named_class(base.Named): - pass - - i = named_class() - assert i.name == 'named_class' - - -def test_Attribute(): - class user__add(base.Attribute): - pass - i = user__add() - assert i.obj_name == 'user' - assert i.attr_name == 'add' - assert i.obj is None - class user(base.Object): - pass - u = user() - i.obj = u - assert i.obj is u - raised = False - try: - i.obj = u - except errors.TwiceSetError: - raised = True - assert raised - - -def test_Method(): - class user__mod(base.Method): - pass - i = user__mod() - assert isinstance(i, base.Attribute) - assert isinstance(i, base.AbstractCommand) - assert i.obj_name == 'user' - assert i.attr_name == 'mod' - assert i.name == 'mod_user' - - -def test_Property(): - class user__firstname(base.Property): - pass - i = user__firstname() - assert isinstance(i, base.Attribute) - assert i.obj_name == 'user' - assert i.attr_name == 'firstname' - assert i.name == 'firstname' - - -def test_Command(): - class dostuff(base.Command): - pass - i = dostuff() - assert isinstance(i, base.AbstractCommand) - assert i.name == 'dostuff' - - - -def test_AttributeCollector(): - class user__add(base.Attribute): - pass - class user__mod(base.Attribute): - pass - class group__add(base.Attribute): - pass - u_a = user__add() - u_m = user__mod() - g_a = group__add() - - ac = base.AttributeCollector() - ac.add(u_a) - ac.add(u_m) - ac.add(g_a) - - assert set(ac) == set(['user', 'group']) - - u = ac['user'] - assert set(u) == set(['add', 'mod']) - assert set(u.values()) == set([u_a, u_m]) - - g = ac['group'] - assert g.keys() == ['add'] - assert g.values() == [g_a] - - -def test_Collector(): - class user(base.Object): - pass - class group(base.Object): - pass - u = user() - g = group() - c = base.Collector() - c.add(u) - c.add(g) - ns = c.ns() - assert isinstance(ns, base.NameSpace) - assert set(ns) == set(['user', 'group']) - assert ns.user is u - assert ns.group is g - - -class test_Registrar(): - r = base.Registrar() - allowed = set(['Command', 'Object', 'Method', 'Property']) - assert set(r) == allowed - - # Some test classes: - class wrong_base(object): - pass - class krbtest(base.Command): - pass - class user(base.Object): - pass - class user__add(base.Method): - pass - class user__firstname(base.Property): - pass - - # Check that exception is raised trying to register an instance of a - # class of a correct base: - raised = False - try: - r(user()) - except errors.RegistrationError: - raised = True - - # Check that exception is raised trying to register class of wrong base: - raised = False - try: - r(wrong_base) - except errors.RegistrationError: - raised = True - assert raised - - # Check that adding a valid class works - for cls in (krbtest, user, user__add, user__firstname): - r(cls) - key = cls.__bases__[0].__name__ - d = r[key] - assert d.keys() == [cls.__name__] - assert d.values() == [cls] - # Check that a copy is returned - d2 = r[key] - assert d2 == d - assert d2 is not d - p = getattr(r, key) - assert isinstance(p, base.Proxy) - # Check that same instance is returned - assert p is getattr(r, key) - assert getattr(p, cls.__name__) is cls - - for base_name in allowed: - for i in r.get_instances(base_name): - assert isinstance(i, getattr(base, base_name)) - - - m = r.get_attrs('Method') - assert isinstance(m, dict) - assert len(m) == 1 - assert len(m['user']) == 1 - assert isinstance(m['user'][0], user__add) - - p = r.get_attrs('Property') - assert isinstance(p, dict) - assert len(p) == 1 - assert len(p['user']) == 1 - assert isinstance(p['user'][0], user__firstname) - - - - - - -def test_API(): - r = base.Registrar() - api = base.API(r) - - class kinit(base.Command): - pass - class user__add(base.Method): - pass - class user__del(base.Method): - pass - class user__firstname(base.Property): - pass - class user__lastname(base.Property): - pass - class user__login(base.Property): - pass - class user(base.Object): - pass - class group(base.Object): - pass - - assert read_only(api, 'objects') is None - assert read_only(api, 'commands') is None - assert read_only(api, 'max_cmd_len') is None - - r(kinit) - r(user__add) - r(user__del) - r(user__firstname) - r(user__lastname) - r(user__login) - r(user) - r(group) - - - api.finalize() - - - objects = read_only(api, 'objects') - assert isinstance(objects, base.NameSpace) - assert len(objects) == 2 - assert list(objects) == ['group', 'user'] - assert type(objects.user) is user - assert type(objects.group) is group - - return - - u = objects.user - assert len(u.methods) == 2 - assert list(u.methods) == ['add', 'del'] - assert len(u.properties) == 3 - assert list(u.properties) == ['firstname', 'lastname', 'login'] - - for m in u.methods(): - assert m.obj is u - for p in u.properties(): - assert p.obj is u - - g = objects.group - assert len(g.methods) == 0 - assert len(g.properties) == 0 - - - assert len(r.commands) == 3 - assert list(r.commands) == sorted(['kinit', 'add_user', 'del_user']) diff --git a/ipalib/tests/test_crud.py b/ipalib/tests/test_crud.py deleted file mode 100644 index 99113c4a4..000000000 --- a/ipalib/tests/test_crud.py +++ /dev/null @@ -1,22 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# 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.crud` module. -"""