From ccd8eb3373b0b195c1bc6efd8650320419c709a6 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sat, 19 Jul 2008 23:40:23 +0000 Subject: 9: Reorganized new work and unit tests based around base.Object being the plugin definining unit --- ipalib/base.py | 113 +++++++++++++++++++-------------- ipalib/crud.py | 71 +++++++-------------- ipalib/tests/test_base.py | 155 ++++++++++++++++++++++++++-------------------- ipalib/tests/test_crud.py | 89 -------------------------- 4 files changed, 177 insertions(+), 251 deletions(-) diff --git a/ipalib/base.py b/ipalib/base.py index 62949eef5..cac6797fe 100644 --- a/ipalib/base.py +++ b/ipalib/base.py @@ -25,51 +25,6 @@ import inspect import exceptions -class Named(object): - prefix = None - - def __init__(self): - clsname = self.__class__.__name__ - assert type(self.prefix) is str - prefix = self.prefix + '_' - if not clsname.startswith(prefix): - raise exceptions.PrefixError(clsname, prefix) - self.__name = clsname[len(prefix):] - self.__name_cli = self.__name.replace('_', '-') - - def __get_name(self): - return self.__name - name = property(__get_name) - - def __get_name_cli(self): - return self.__name_cli - name_cli = property(__get_name_cli) - - -class Command(Named): - prefix = 'cmd' - - def normalize(self, kw): - raise NotImplementedError - - def validate(self, kw): - raise NotImplementedError - - def execute(self, kw): - raise NotImplementedError - - def __call__(self, **kw): - normalized = self.normalize(kw) - invalid = self.validate(normalized) - if invalid: - return invalid - return self.execute(normalize) - - -class Argument(object): - pass - - class NameSpace(object): """ A read-only namespace of (key, value) pairs that can be accessed @@ -103,8 +58,10 @@ class NameSpace(object): def __init__(self, kw, order=None): """ - The single constructor argument `kw` is a dict of the (key, value) - pairs to be in this NameSpace instance. + 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) @@ -141,7 +98,8 @@ class NameSpace(object): def __iter__(self): """ - Yields the names in this NameSpace in ascending order. + Yields the names in this NameSpace in ascending order, or in the + the order specified in `order` kw arg. For example: @@ -161,6 +119,65 @@ class NameSpace(object): return len(self.__keys) +class Named(object): + def __get_name(self): + return self.__class__.__name__ + name = property(__get_name) + + +class ObjectMember(Named): + def __init__(self, obj): + self.__obj = obj + + def __get_obj(self): + return self.__obj + obj = property(__get_obj) + + +class Command(ObjectMember): + def __get_full_name(self): + return '%s_%s' % (self.name, self.obj.name) + full_name = property(__get_full_name) + + +class Attribute(ObjectMember): + def __get_full_name(self): + return '%s_%s' % (self.obj.name, self.name) + full_name = property(__get_full_name) + + +class Object(Named): + def __init__(self): + self.__commands = self.__build_ns(self.get_commands) + self.__attributes = self.__build_ns(self.get_attributes, True) + + def __get_commands(self): + return self.__commands + commands = property(__get_commands) + + def __get_attributes(self): + return self.__attributes + attributes = property(__get_attributes) + + def __build_ns(self, callback, preserve=False): + d = {} + o = [] + for cls in callback(): + i = cls(self) + assert i.name not in d + d[i.name] = i + o.append(i.name) + if preserve: + return NameSpace(d, order=o) + return NameSpace(d) + + def get_commands(self): + raise NotImplementedError + + def get_attributes(self): + raise NotImplementedError + + class API(object): __cmd = None __objects = None diff --git a/ipalib/crud.py b/ipalib/crud.py index 1be727673..afbad47ac 100644 --- a/ipalib/crud.py +++ b/ipalib/crud.py @@ -18,66 +18,43 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ - +Base classes for objects with CRUD functionality. """ -from base import NameSpace - -class Named(object): - def __get_name(self): - return self.__class__.__name__ - name = property(__get_name) - -class ObjectMember(Named): - def __init__(self, obj): - self.__obj = obj +import base - def __get_obj(self): - return self.__obj - obj = property(__get_obj) +class create(base.Command): + pass -class Command(ObjectMember): - def __get_full_name(self): - return '%s_%s' % (self.name, self.obj.name) - full_name = property(__get_full_name) +class retrieve(base.Command): + pass -class Attribute(ObjectMember): - def __get_full_name(self): - return '%s_%s' % (self.obj.name, self.name) - full_name = property(__get_full_name) +class update(base.Command): + pass -class Object(Named): - def __init__(self): - self.__commands = self.__build_ns(self.get_commands) - self.__attributes = self.__build_ns(self.get_attributes, True) - def __get_commands(self): - return self.__commands - commands = property(__get_commands) +class delete(base.Command): + pass - def __get_attributes(self): - return self.__attributes - attributes = property(__get_attributes) - def __build_ns(self, callback, preserve=False): - d = {} - o = [] - for cls in callback(): - i = cls(self) - assert i.name not in d - d[i.name] = i - o.append(i.name) - if preserve: - return NameSpace(d, order=o) - return NameSpace(d) +class search(base.Command): + pass - def __get_commands(self): - return +class user(base.Object): def get_commands(self): - raise NotImplementedError + return [ + create, + retrieve, + update, + delete, + ] def get_attributes(self): - raise NotImplementedError + return [ + givenName, + sn, + login, + ] diff --git a/ipalib/tests/test_base.py b/ipalib/tests/test_base.py index 81794d7ac..31b109941 100644 --- a/ipalib/tests/test_base.py +++ b/ipalib/tests/test_base.py @@ -56,61 +56,6 @@ class ClassChecker(object): return self.new(*self.args(), **self.kw()) -class test_Named: - """ - Unit tests for `Named` class. - """ - cls = base.Named - - def new(self): - class tst_verb_object(self.cls): - prefix = 'tst' - return tst_verb_object() - - def test_prefix(self): - """ - Test prefix exception. - """ - # Test Example class: - class Example(self.cls): - prefix = 'eg' - - # Two test subclasses: - class do_stuff(Example): - pass - class eg_do_stuff(Example): - pass - - # Test that PrefixError is raised with incorrectly named subclass: - raised = False - try: - do_stuff() - except exceptions.PrefixError: - raised = True - assert raised - - # Test that correctly named subclass works: - eg_do_stuff() - - def test_name(self): - """ - Test Named.name property. - """ - obj = self.new() - assert read_only(obj, 'name') == 'verb_object' - - def test_name_cli(self): - """ - Test Named.name_cli property. - """ - obj = self.new() - assert read_only(obj, 'name_cli') == 'verb-object' - - - - - - class test_NameSpace: """ Unit tests for `NameSpace` class. @@ -238,17 +183,93 @@ class test_NameSpace: assert len(kw) == len(ns) == 3 -class test_Command(ClassChecker): - class cmd_some_command(base.Command): +def test_Command(): + class user(object): + name = 'user' + class add(base.Command): + pass + i = add(user()) + assert i.name == 'add' + assert i.full_name == 'add_user' + + +def test_Attribute(): + class user(object): + name = 'user' + class sn(base.Attribute): pass - cls = cmd_some_command + i = sn(user()) + assert i.name == 'sn' + assert i.full_name == 'user_sn' + + +def test_Object(): + class create(base.Command): + pass + + class retrieve(base.Command): + pass + + class update(base.Command): + pass + + class delete(base.Command): + pass + + class givenName(base.Attribute): + pass + + class sn(base.Attribute): + pass + + class login(base.Attribute): + pass + - def test_fresh(self): - c = self.new() - assert isinstance(c, base.Named) - assert c.name == 'some_command' - assert c.name_cli == 'some-command' - assert callable(c) + class user(base.Object): + def get_commands(self): + return [ + create, + retrieve, + update, + delete, + ] + + def get_attributes(self): + return [ + givenName, + sn, + login, + ] + + i = user() + assert i.name == 'user' + + # Test commands: + commands = i.commands + assert isinstance(commands, base.NameSpace) + assert list(commands) == ['create', 'delete', 'retrieve', 'update'] + assert len(commands) == 4 + for name in commands: + cls = locals()[name] + cmd = commands[name] + assert type(cmd) is cls + assert getattr(commands, name) is cmd + assert cmd.name == name + assert cmd.full_name == ('%s_user' % name) + + # Test attributes: + attributes = i.attributes + assert isinstance(attributes, base.NameSpace) + assert list(attributes) == ['givenName', 'sn', 'login'] + assert len(attributes) == 3 + for name in attributes: + cls = locals()[name] + attr = attributes[name] + assert type(attr) is cls + assert getattr(attributes, name) is attr + assert attr.name == name + assert attr.full_name == ('user_%s' % name) class test_API: @@ -262,14 +283,14 @@ class test_API: """ return base.API() - def test_fresh(self): + def dont_fresh(self): """ Test expectations of a fresh API instance. """ api = self.new() assert read_only(api, 'cmd') is None - def test_register_command(self): + def dont_register_command(self): api = self.new() class cmd_my_command(base.Command): @@ -314,7 +335,7 @@ class test_API: # Check that override=True works: api.register_command(cmd_my_command, override=True) - def test_finalize(self): + def dont_finalize(self): api = self.new() assert read_only(api, 'cmd') is None diff --git a/ipalib/tests/test_crud.py b/ipalib/tests/test_crud.py index 12ee1009b..99113c4a4 100644 --- a/ipalib/tests/test_crud.py +++ b/ipalib/tests/test_crud.py @@ -20,92 +20,3 @@ """ Unit tests for `ipalib.crud` module. """ - -from ipalib import crud, base, exceptions - -class create(crud.Command): - pass - -class retrieve(crud.Command): - pass - -class update(crud.Command): - pass - -class delete(crud.Command): - pass - -class givenName(crud.Attribute): - pass - -class sn(crud.Attribute): - pass - -class login(crud.Attribute): - pass - - -class user(crud.Object): - def get_commands(self): - return [ - create, - retrieve, - update, - delete, - ] - - def get_attributes(self): - return [ - givenName, - sn, - login, - ] - - -def test_Named(): - class named_class(crud.Named): - pass - - n = named_class() - assert n.name == 'named_class' - - -def test_Command(): - class user(object): - name = 'user' - class add(crud.Command): - pass - i = add(user()) - assert i.name == 'add' - assert i.full_name == 'add_user' - - -def test_Object(): - i = user() - assert i.name == 'user' - - # Test commands: - commands = i.commands - assert isinstance(commands, base.NameSpace) - assert list(commands) == ['create', 'delete', 'retrieve', 'update'] - assert len(commands) == 4 - for name in commands: - cls = globals()[name] - cmd = commands[name] - assert type(cmd) is cls - assert getattr(commands, name) is cmd - assert cmd.name == name - assert cmd.full_name == ('%s_user' % name) - - # Test attributes: - attributes = i.attributes - assert isinstance(attributes, base.NameSpace) - assert list(attributes) == ['givenName', 'sn', 'login'] - assert len(attributes) == 3 - for name in attributes: - cls = globals()[name] - attr = attributes[name] - assert type(attr) is cls - assert getattr(attributes, name) is attr - assert attr.name == name - assert attr.full_name == ('user_%s' % name) -- cgit