[Python-checkins] distutils2: Add a wrapper around the two client implementations.

tarek.ziade python-checkins at python.org
Sun Aug 8 11:50:46 CEST 2010


tarek.ziade pushed d92211963592 to distutils2:

http://hg.python.org/distutils2/rev/d92211963592
changeset:   460:d92211963592
user:        Alexis Metaireau <ametaireau at gmail.com>
date:        Tue Jul 27 15:22:15 2010 +0200
summary:     Add a wrapper around the two client implementations.
files:       src/distutils2/index/wrapper.py

diff --git a/src/distutils2/index/wrapper.py b/src/distutils2/index/wrapper.py
new file mode 100644
--- /dev/null
+++ b/src/distutils2/index/wrapper.py
@@ -0,0 +1,89 @@
+import xmlrpc
+import simple
+
+_WRAPPER_MAPPINGS = {'get_release': 'simple',
+                     'get_releases': 'simple',
+                     'search_projects': 'simple', }
+
+_WRAPPER_INDEXES = {'xmlrpc': xmlrpc.Client,
+                    'simple': simple.Crawler}
+
+def switch_index_if_fails(func, wrapper):
+    """Decorator that switch of index (for instance from xmlrpc to simple)
+    if the first mirror return an empty list or raises an exception.
+    """
+    def decorator(*args, **kwargs):
+        retry = True
+        exception = None
+        methods = [func]
+        for f in wrapper._indexes.values():
+            if f != func.im_self and hasattr(f, func.__name__):
+                methods.append(getattr(f, func.__name__))
+        for method in methods:
+            try:
+                response = method(*args, **kwargs)
+                retry = False
+            except Exception, e:
+                exception = e
+            if not retry:
+                break
+        if retry and exception:
+            raise exception
+        else:
+            return response
+    return decorator
+
+
+class ClientWrapper(object):
+    """Wrapper around simple and xmlrpc clients,
+
+    Choose the best implementation to use depending the needs.
+    If one of the indexes returns an error, try to use others indexes.
+
+    :param index: tell wich index to rely on by default.
+    :param index_classes: a dict of name:class to use as indexes.
+    :param indexes: a dict of name:index already instanciated
+    :param mappings: the mappings to use for this wrapper
+    """
+
+    def __init__(self, default_index='simple', index_classes=_WRAPPER_INDEXES,
+                 indexes={}, mappings=_WRAPPER_MAPPINGS):
+        self._projects = {}
+        self._mappings = mappings
+        self._indexes = indexes
+        self._default_index = default_index
+
+        # instanciate the classes and set their _project attribute to the one
+        # of the wrapper.
+        for name, cls in index_classes.items():
+            obj = self._indexes.setdefault(name, cls())
+            obj._projects = self._projects
+
+    def __getattr__(self, method_name):
+        """When asking for methods of the wrapper, return the implementation of
+        the wrapped classes, depending the mapping.
+
+        Decorate the methods to switch of implementation if an error occurs
+        """
+        real_method = None
+        if method_name in _WRAPPER_MAPPINGS:
+            obj = self._indexes[_WRAPPER_MAPPINGS[method_name]]
+            real_method = getattr(obj, method_name)
+        else:
+            # the method is not defined in the mappings, so we try first to get
+            # it via the default index, and rely on others if needed.
+            try:
+                real_method = getattr(self._indexes[self._default_index], 
+                                      method_name)
+            except AttributeError:
+                other_indexes = [i for i in self._indexes 
+                                 if i != self._default_index]
+                for index in other_indexes:
+                    real_method = getattr(self._indexes[index], method_name, None)
+                    if real_method:
+                        break
+        if real_method:
+            return switch_index_if_fails(real_method, self)
+        else:
+            raise AttributeError("No index have attribute '%s'" % method_name)
+        

--
Repository URL: http://hg.python.org/distutils2


More information about the Python-checkins mailing list