From 10c7d692f0de37d5dea0f6b1188d7f147a836fca Mon Sep 17 00:00:00 2001
From: Wannes Rombouts <wapiflapi@yahoo.fr>
Date: Thu, 30 May 2013 15:04:01 +0200
Subject: [PATCH] Refactored pyxml.Entries to handle lists in adition to dicts.
 Some python metaclass magic going on...

---
 src/pyxml.py  | 51 +++++++++++++++++++++++++++------------------------
 src/server.py |  6 ++----
 2 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/src/pyxml.py b/src/pyxml.py
index 080023c..9d11236 100644
--- a/src/pyxml.py
+++ b/src/pyxml.py
@@ -28,30 +28,33 @@ import xml.etree.ElementTree as etree
 from xml.etree.ElementTree import Element
 from xml.sax.saxutils import escape
 
-class Entries(dict):
-    """Helper class to specify how dictonaries should be handled in more detail.
-    """
-
-    def __init__(self, *args, **kwargs):
-        """ All arguments are passed to dict(), except for:
-        tag_name: this can be used to specify the tag name of the dict's entries.
-        key_name: if a tag_name is used this will be the attribute's name.
-
-        By default no tag name is used and the dict's keys are used as tags.
-        """
+# Here we have the Entries, it wraps either a list or a dict.
+# Its not trivial because we want to inherit from a list or
+# from a dict, but we want both instances to inherit from Entries.
+# Also we want the factory to be Entries and not a function.
+class Entries(object):
+    def __new__(clazz, obj, *args, **kwargs):
+        class _Entries(Entries, type(obj)):
+            def __init__(self, *args, **kwargs):
+                # Try to be as transparent as possible.
+                self.tag_name = kwargs.pop("tag_name", None)
+                self.key_name = kwargs.pop("key_name", "key")
+                type(obj).__init__(self, *args, **kwargs)
+
+            # Now define get_hints, the ifs are not in it because we want
+            # the exception to be raised at instanciation.
+            if isinstance(obj, list):
+                def get_hints(self):
+                    return (xml_list, self.tag_name) if self.tag_name else (xml_list, ())
+            elif isinstance(obj, dict):
+                def get_hints(self):
+                    return (xml_dict, (self.tag_name, self.key_name)) if self.tag_name else (xml_dict, ())
+            else:
+                raise TypeError("Entries must be given a list or a dict as first argument.")
+
+        # We need to call __new__ on the parent of our _Entries
+        return type(obj).__new__(_Entries, *args, **kwargs)
 
-        # Let's try to be as transparent as possible.
-        self.tag_name = kwargs.pop("tag_name", None)
-        self.key_name = kwargs.pop("key_name", "key")
-
-        dict.__init__(self, *args, **kwargs)
-
-    def get_dict_hints(self):
-        "Generating hints for %s" % self
-        if self.tag_name:
-            return self.tag_name, self.key_name
-        else:
-            return None
 
 def href(link, element=None):
     """Builds an atom:link object for the link."""
@@ -116,7 +119,7 @@ def default_xml_mapper(obj, obj_name,
     if obj == None:
         return None, None
     elif isinstance(obj, Entries):
-        return xml_dict, obj.get_dict_hints()
+        return obj.get_hints()
     elif obj_name == "href":
         return xml_href, None
     elif isinstance(obj, dict):
diff --git a/src/server.py b/src/server.py
index 87e5046..2c32b1f 100755
--- a/src/server.py
+++ b/src/server.py
@@ -540,10 +540,8 @@ class style(object):
 
         return {
             "name": s_name,
-            "sldVersion": Entries([
-                #TODO: Return the correct value...
-                "1.0.0"
-                ], tag_name="version"),
+            #TODO: Return the correct value...
+            "sldVersion": Entries(["1.0.0"], tag_name="version"),
             "filename": s_name + ".sld",
             "href": "%s/maps/%s/styles/%s.sld" % (web.ctx.home, map_name, s_name)
             }
-- 
GitLab