]> git.llucax.com Git - software/pymin.git/commitdiff
Add support to "operation tagging" to ListSubHandler and DictSubHandler.
authorLeandro Lucarella <llucax@gmail.com>
Thu, 11 Oct 2007 21:06:57 +0000 (18:06 -0300)
committerLeandro Lucarella <llucax@gmail.com>
Thu, 11 Oct 2007 21:06:57 +0000 (18:06 -0300)
"Operation tagging" means that if the contained objects has an _add,
_update or _delete attribute, it set them to true when the item is
added, updated or deleted respectively (in case that it's deleted, it's
not removed from the container, but it's not listed either, i.e. the
items are "logically" deleted, not really removed from the container).

Now ListSubHandler and DictSubHandler ihnerit from a new class
ContainerSubHandler which handles 95% of the code. Because of this, now
the "magic" attributes starts with _cont_ instead of _list_ or _dict_.
Existing handler were updated, but new ones should take this into
account.

TODO
pymin/services/dhcp/__init__.py
pymin/services/firewall/__init__.py
pymin/services/proxy/__init__.py
pymin/services/util.py

diff --git a/TODO b/TODO
index 40b489a5ea1e887738c9528ccccb3994aa90d120..2aead12fbcb348447997a2d39d89c8f5c7467159 100644 (file)
--- a/TODO
+++ b/TODO
@@ -8,6 +8,12 @@ Ideas / TODO:
   * Logging.
   * Paths.
 
+* SubHandlers:
+  * ComposeDictSubHandler con soporte de dirty/del/add (para ip y DNS).
+  * Agregar SimpleDictSubHandler? (que no use una clase, que use un dict
+    de strings directamente, para Proxy Users por ej.). Ídem List.
+  * Agregar SetSubHandler? (para Proxy Hosts)
+
 * Agregar logging.
 
 * Agregar validación con formencode.
index dd2fa9d0f2b4438f6a4b549dd6f616896614389a..6e6f19829040f66b8764ac54d3701b26a578b6d2 100644 (file)
@@ -54,8 +54,8 @@ class HostHandler(DictSubHandler):
 
     handler_help = u"Manage DHCP hosts"
 
-    _dict_subhandler_attr = 'hosts'
-    _dict_subhandler_class = Host
+    _cont_subhandler_attr = 'hosts'
+    _cont_subhandler_class = Host
 
 class DhcpHandler(Restorable, ConfigWriter, InitdHandler, TransactionalHandler,
                   ParametersHandler):
index b0784bfbb62c5569413fc1f75da6440037b0636b..c13ad010f18e2fc751e98fa0a2de80ef13d7e240 100644 (file)
@@ -81,8 +81,8 @@ class RuleHandler(ListSubHandler):
 
     handler_help = u"Manage firewall rules"
 
-    _list_subhandler_attr = 'rules'
-    _list_subhandler_class = Rule
+    _cont_subhandler_attr = 'rules'
+    _cont_subhandler_class = Rule
 
 class FirewallHandler(Restorable, ConfigWriter, ServiceHandler,
                       TransactionalHandler):
index 0577938271deced0545b6786caf08fa8f6545fe4..85bafd8c2d44cecd0299b49ce9ae240a51ca5e7b 100644 (file)
@@ -35,8 +35,8 @@ class HostHandler(DictSubHandler):
 
     handler_help = u"Manage proxy hosts"
 
-    _dict_subhandler_attr = 'hosts'
-    _dict_subhandler_class = Host
+    _cont_subhandler_attr = 'hosts'
+    _cont_subhandler_class = Host
 
 class User(Sequence):
     def __init__(self, name, password):
@@ -52,8 +52,8 @@ class UserHandler(DictSubHandler):
 
     handler_help = u"Manage proxy users"
 
-    _dict_subhandler_attr = 'users'
-    _dict_subhandler_class = User
+    _cont_subhandler_attr = 'users'
+    _cont_subhandler_class = User
 
 class ProxyHandler(Restorable, ConfigWriter, InitdHandler,
                    TransactionalHandler, ParametersHandler):
index 95a07e9992d8b0f9b92df39e7a1c41e2cd34f6aa..8d3775ecaa61a2f0e1f12fcd1ff718035b72c424 100644 (file)
@@ -590,162 +590,184 @@ class SubHandler(Handler):
         r"Initialize the object, see the class documentation for details."
         self.parent = parent
 
-class ListSubHandler(SubHandler):
-    r"""ListSubHandler(parent) -> ListSubHandler instance.
-
-    This is a helper class to inherit from to automatically handle subcommands
-    that operates over a list parent attribute.
-
-    The list attribute to handle and the class of objects that it contains can
-    be defined by calling the constructor or in a more declarative way as
-    class attributes, like:
-
-    class TestHandler(ListSubHandler):
-        _list_subhandler_attr = 'some_list'
-        _list_subhandler_class = SomeClass
-
-    This way, the parent's some_list attribute (self.parent.some_list) will be
-    managed automatically, providing the commands: add, update, delete, get,
-    list and show. New items will be instances of SomeClass, which should
-    provide a cmp operator to see if the item is on the list and an update()
-    method, if it should be possible to modify it.
+class ContainerSubHandler(SubHandler):
+    r"""ContainerSubHandler(parent) -> ContainerSubHandler instance.
+
+    This is a helper class to implement ListSubHandler and DictSubHandler. You
+    should not use it directly.
+
+    The container attribute to handle and the class of objects that it
+    contains can be defined by calling the constructor or in a more declarative
+    way as class attributes, like:
+
+    class TestHandler(ContainerSubHandler):
+        _cont_subhandler_attr = 'some_cont'
+        _cont_subhandler_class = SomeClass
+
+    This way, the parent's some_cont attribute (self.parent.some_cont)
+    will be managed automatically, providing the commands: add, update,
+    delete, get and show. New items will be instances of SomeClass,
+    which should provide a cmp operator to see if the item is on the
+    container and an update() method, if it should be possible to modify
+    it. If SomeClass has an _add, _update or _delete attribute, it set
+    them to true when the item is added, updated or deleted respectively
+    (in case that it's deleted, it's not removed from the container,
+    but it's not listed either).
     """
 
     def __init__(self, parent, attr=None, cls=None):
         r"Initialize the object, see the class documentation for details."
         self.parent = parent
         if attr is not None:
-            self._list_subhandler_attr = attr
+            self._cont_subhandler_attr = attr
         if cls is not None:
-            self._list_subhandler_class = cls
+            self._cont_subhandler_class = cls
+
+    def _cont(self):
+        return getattr(self.parent, self._cont_subhandler_attr)
 
-    def _list(self):
-        return getattr(self.parent, self._list_subhandler_attr)
+    def _vcont(self):
+        if isinstance(self._cont(), dict):
+            return dict([(k, i) for (k, i) in self._cont().items()
+                    if not hasattr(i, '_delete') or not i._delete])
+        return [i for i in self._cont()
+                if not hasattr(i, '_delete') or not i._delete]
 
     @handler(u'Add a new item')
     def add(self, *args, **kwargs):
         r"add(...) -> None :: Add an item to the list."
-        item = self._list_subhandler_class(*args, **kwargs)
-        if item in self._list():
+        item = self._cont_subhandler_class(*args, **kwargs)
+        if hasattr(item, '_add'):
+            item._add = True
+        key = item
+        if isinstance(self._cont(), dict):
+            key = item.as_tuple()[0]
+        # do we have the same item? then raise an error
+        if key in self._vcont():
             raise ItemAlreadyExistsError(item)
-        self._list().append(item)
+        # do we have the same item, but logically deleted? then update flags
+        if key in self._cont():
+            index = key
+            if not isinstance(self._cont(), dict):
+                index = self._cont().index(item)
+            if hasattr(item, '_add'):
+                self._cont()[index]._add = False
+            if hasattr(item, '_delete'):
+                self._cont()[index]._delete = False
+        else: # it's *really* new
+            if isinstance(self._cont(), dict):
+                self._cont()[key] = item
+            else:
+                self._cont().append(item)
 
     @handler(u'Update an item')
     def update(self, index, *args, **kwargs):
-        r"update(index, ...) -> None :: Update an item of the list."
+        r"update(index, ...) -> None :: Update an item of the container."
         # TODO make it right with metaclasses, so the method is not created
         # unless the update() method really exists.
         # TODO check if the modified item is the same of an existing one
-        index = int(index) # TODO validation
-        if not hasattr(self._list_subhandler_class, 'update'):
+        if not isinstance(self._cont(), dict):
+            index = int(index) # TODO validation
+        if not hasattr(self._cont_subhandler_class, 'update'):
             raise CommandNotFoundError(('update',))
         try:
-            self._list()[index].update(*args, **kwargs)
+            item = self._vcont()[index]
+            item.update(*args, **kwargs)
+            if hasattr(item, '_update'):
+                item._update = True
         except IndexError:
             raise ItemNotFoundError(index)
 
     @handler(u'Delete an item')
     def delete(self, index):
-        r"delete(index) -> None :: Delete an item of the list."
-        index = int(index) # TODO validation
+        r"delete(index) -> None :: Delete an item of the container."
+        if not isinstance(self._cont(), dict):
+            index = int(index) # TODO validation
         try:
-            return self._list().pop(index)
+            item = self._vcont()[index]
+            if hasattr(item, '_delete'):
+                item._delete = True
+            else:
+                del self._cont()[index]
+            return item
         except IndexError:
             raise ItemNotFoundError(index)
 
     @handler(u'Get information about an item')
     def get(self, index):
-        r"get(index) -> Host :: List all the information of an item."
-        index = int(index) # TODO validation
+        r"get(index) -> item :: List all the information of an item."
+        if not isinstance(self._cont(), dict):
+            index = int(index) # TODO validation
         try:
-            return self._list()[index]
+            return self._vcont()[index]
         except IndexError:
             raise ItemNotFoundError(index)
 
-    @handler(u'Get how many items are in the list')
-    def len(self):
-        r"len() -> int :: Get how many items are in the list."
-        return len(self._list())
-
     @handler(u'Get information about all items')
     def show(self):
-        r"show() -> list of Hosts :: List all the complete items information."
-        return self._list()
+        r"show() -> list of items :: List all the complete items information."
+        if isinstance(self._cont(), dict):
+            return self._cont().values()
+        return self._vcont()
 
-class DictSubHandler(SubHandler):
-    r"""DictSubHandler(parent) -> DictSubHandler instance.
+class ListSubHandler(ContainerSubHandler):
+    r"""ListSubHandler(parent) -> ListSubHandler instance.
 
     This is a helper class to inherit from to automatically handle subcommands
-    that operates over a dict parent attribute.
+    that operates over a list parent attribute.
 
-    The dict attribute to handle and the class of objects that it contains can
+    The list attribute to handle and the class of objects that it contains can
     be defined by calling the constructor or in a more declarative way as
     class attributes, like:
 
-    class TestHandler(DictSubHandler):
-        _dict_subhandler_attr = 'some_dict'
-        _dict_subhandler_class = SomeClass
+    class TestHandler(ListSubHandler):
+        _cont_subhandler_attr = 'some_list'
+        _cont_subhandler_class = SomeClass
 
-    This way, the parent's some_dict attribute (self.parent.some_dict) will be
+    This way, the parent's some_list attribute (self.parent.some_list) will be
     managed automatically, providing the commands: add, update, delete, get,
     list and show. New items will be instances of SomeClass, which should
-    provide a constructor with at least the key value and an update() method,
-    if it should be possible to modify it.
+    provide a cmp operator to see if the item is on the list and an update()
+    method, if it should be possible to modify it. If SomeClass has an _add,
+    _update or _delete attribute, it set them to true when the item is added,
+    updated or deleted respectively (in case that it's deleted, it's not
+    removed from the list, but it's not listed either).
     """
 
-    def __init__(self, parent, attr=None, cls=None):
-        r"Initialize the object, see the class documentation for details."
-        self.parent = parent
-        if attr is not None:
-            self._dict_subhandler_attr = attr
-        if cls is not None:
-            self._dict_subhandler_class = cls
+    @handler(u'Get how many items are in the list')
+    def len(self):
+        r"len() -> int :: Get how many items are in the list."
+        return len(self._vcont())
 
-    def _dict(self):
-        return getattr(self.parent, self._dict_subhandler_attr)
+class DictSubHandler(ContainerSubHandler):
+    r"""DictSubHandler(parent) -> DictSubHandler instance.
 
-    @handler(u'Add a new item')
-    def add(self, key, *args, **kwargs):
-        r"add(key, ...) -> None :: Add an item to the dict."
-        item = self._dict_subhandler_class(key, *args, **kwargs)
-        if key in self._dict():
-            raise ItemAlreadyExistsError(key)
-        self._dict()[key] = item
+    This is a helper class to inherit from to automatically handle subcommands
+    that operates over a dict parent attribute.
 
-    @handler(u'Update an item')
-    def update(self, key, *args, **kwargs):
-        r"update(key, ...) -> None :: Update an item of the dict."
-        # TODO make it right with metaclasses, so the method is not created
-        # unless the update() method really exists.
-        if not hasattr(self._dict_subhandler_class, 'update'):
-            raise CommandNotFoundError(('update',))
-        if not key in self._dict():
-            raise ItemNotFoundError(key)
-        self._dict()[key].update(*args, **kwargs)
+    The dict attribute to handle and the class of objects that it contains can
+    be defined by calling the constructor or in a more declarative way as
+    class attributes, like:
 
-    @handler(u'Delete an item')
-    def delete(self, key):
-        r"delete(key) -> None :: Delete an item of the dict."
-        if not key in self._dict():
-            raise ItemNotFoundError(key)
-        del self._dict()[key]
+    class TestHandler(DictSubHandler):
+        _cont_subhandler_attr = 'some_dict'
+        _cont_subhandler_class = SomeClass
 
-    @handler(u'Get information about an item')
-    def get(self, key):
-        r"get(key) -> Host :: List all the information of an item."
-        if not key in self._dict():
-            raise ItemNotFoundError(key)
-        return self._dict()[key]
+    This way, the parent's some_dict attribute (self.parent.some_dict) will be
+    managed automatically, providing the commands: add, update, delete, get,
+    list and show. New items will be instances of SomeClass, which should
+    provide a constructor with at least the key value, an as_tuple() method
+    and an update() method,     if it should be possible to modify
+    it. If SomeClass has an _add, _update or _delete attribute, it set
+    them to true when the item is added, updated or deleted respectively
+    (in case that it's deleted, it's not removed from the dict, but it's
+    not listed either).
+    """
 
     @handler(u'List all the items by key')
     def list(self):
         r"list() -> tuple :: List all the item keys."
-        return self._dict().keys()
-
-    @handler(u'Get information about all items')
-    def show(self):
-        r"show() -> list of Hosts :: List all the complete items information."
-        return self._dict().values()
+        return self._cont().keys()
 
 
 if __name__ == '__main__':