Commits

timhanus committed d363d6c

move CacheRegion.wrap() to its own function rather than as part of configure. Clean up documentation some more

  • Participants
  • Parent commits ce04f94

Comments (0)

Files changed (4)

docs/build/usage.rst

             log.debug('Setting Cache Key: %s' % key)
             self.proxied.set(key, value)
             
-A backend proxy can be attached to a region in the call to :meth:`.CacheRegion.configure`::
+    
+`.ProxyBackend`s can be be configured to optionally take arguments (as long as the 
+ProxyBackend.__init__() method is called properly.  This class will take a retry 
+count value on creation.  In the event of an exception on delete() it will retry 
+this many times before returning.::
 
+    from dogpile.cache.proxy import ProxyBackend
+    
+    class RetryDeleteProxy(ProxyBackend):
+        def __init__(self, retry_count=5):
+            ProxyBackend.__init__(self)
+            self.retry_count = retry_count
+            
+        def delete(self, key):
+            retries = self.retry_count
+            while retries > 0:
+                retries -= 1
+                try:
+                    self.proxied.delete(key)
+                    return
+                    
+                except:
+                    pass
+                    
+The wrap parameter of the :meth:`.CacheRegion.configure` method can take multiple 
+proxies. It also can take either `.ProxyBackend` classes or instance objects.  
+Putting the two examples above together would look like this::
+ 
     from dogpile.cache import make_region
+    
+    retry_proxy = RetryDeleteProxy(5)
 
     region = make_region().configure(
         'dogpile.cache.pylibmc',
         arguments = {
             'url':["127.0.0.1"],
         },
-        wrap = [ LoggingProxy ] 
+        wrap = [ LoggingProxy, retry_proxy ] 
     )
     
+In the above example the LoggingProxy would wrap retry_proxy which would in turn
+wrap the real dogpile.cache.pylibmc backend.  
+                
+        
+
+
+
+
+ 
+    
 
 
 

dogpile/cache/proxy.py

         
     def wrap(self, backend):
         ''' Take a backend as an argument and setup the self.proxied property.  
-        Return an object that be used as a backend by a `.CacheRegion` object.
+        Return an object that be used as a backend by a `CacheRegion` object.
         '''
         assert(isinstance(backend, CacheBackend) or isinstance(backend, ProxyBackend))
         self.proxied = backend

dogpile/cache/region.py

          directly to the constructor of the :class:`.CacheBackend`
          in use, though is typically a dictionary.
          
-        :param wrap:   Optional.  A list of :class:`.proxy.ProxyBackend`
-         classes that will wrap the backend.  Elements in this list can 
-         either be classes that inherit from ProxyBackend (in which case 
-         they will be initialized) or ProxyBackend objects that have 
-         already been initialized elsewhere.  Each element of the list
-         wraps the subsequent elements so wrap[0] will wrap wrap[1] which
-         in turn wraps wrap[2] and so on.  
+        :param wrap:   Optional.  A list of ProxyBackend classes that 
+         will wrap the backend.  Elements in list can either be classes
+         or instances of ProxyBackend
+         """
 
-        """
         if "backend" in self.__dict__:
             raise Exception(
                     "This region is already "
 
         self._lock_registry = NameRegistry(self._create_mutex)
         
-        if wrap:
+        if getattr(wrap,'__iter__', False):
             for wrapper in reversed(wrap):
-                if type(wrapper) == type:
-                    wrapper = wrapper()
-                
-                if not issubclass(type(wrapper), ProxyBackend):
-                    raise Exception(
-                            "Type %s is not a valid ProxyBackend"
-                            % type(wrapper)
-                            )
-                    
-                self.backend = wrapper.wrap(self.backend)
+                self.wrap(wrapper)
                 
-                
-
         return self
     
+    def wrap(self, proxy):
+        ''' Takes a ProxyBackend instance or class and wraps the
+        attached backend. '''
+        
+        # if we were passed a type rather than an instance then 
+        # initialize it.  
+        if type(proxy) == type:
+            proxy = proxy()
+                
+        if not issubclass(type(proxy), ProxyBackend):
+            raise Exception("Type %s is not a valid ProxyBackend"
+                    % type(proxy))
+                        
+        self.backend = proxy.wrap(self.backend)
+          
+    
     def _mutex(self, key):
         return self._lock_registry.get(key)
 

tests/cache/test_region.py

     class UsedKeysProxy(ProxyBackend):
         ''' Keep a counter of hose often we set a particular key'''
         
-        def __init__(self, count, *args, **kwargs):
+        def __init__(self, *args, **kwargs):
             super(ProxyBackendTest.UsedKeysProxy, self).__init__(*args, **kwargs)
-            self.count = count
             self._key_count = defaultdict(lambda: 0)
             
         def setcount(self, key):
             self._key_count[key] += 1
             self.proxied.set(key, value)
             
+    class NeverSetProxy(ProxyBackend):
+        ''' A totally contrived example of a Proxy that we pass arguments to. 
+        Never set a key that matches never_set ''' 
+        
+        def __init__(self, never_set, *args, **kwargs):
+            super(ProxyBackendTest.NeverSetProxy, self).__init__(*args, **kwargs)
+            self.never_set = never_set
+            self._key_count = defaultdict(lambda: 0)
+            
+        def set(self, key, value):
+            if key != self.never_set:
+                self.proxied.set(key, value)
+
+            
 
             
     def _region(self, init_args={}, config_args={}, backend="mock"):
         return reg
     
     def test_counter_proxies(self):
+        # count up the gets and sets and make sure they are passed through
+        # to the backend properly.  Test that methods not overridden
+        # continue to work
+        
         reg = self._region(config_args={"wrap": [ 
             ProxyBackendTest.GetCounterProxy, 
             ProxyBackendTest.SetCounterProxy ]})
             is_(v, NO_VALUE)
             
     def test_instance_proxies(self):
-        ''' Test that we can create an instance of a new proxy and 
-        pass that to make_region instead of the class.  The two instances
-        should not interfere with each other ''' 
+        # Test that we can create an instance of a new proxy and 
+        # pass that to make_region instead of the class.  The two instances
+        # should not interfere with each other  
         proxy_num = ProxyBackendTest.UsedKeysProxy(5)
         proxy_abc = ProxyBackendTest.UsedKeysProxy(5)
         reg_num = self._region(config_args={"wrap": [ proxy_num ]}) 
         eq_(proxy_abc.setcount('a'),2)
         eq_(proxy_abc.setcount('g'),1)
         eq_(proxy_abc.setcount('9'),0)
+        
+    def test_argument_proxies(self):
+        # Test that we can pass an argument to Proxy on creation  
+        proxy = ProxyBackendTest.NeverSetProxy(5)
+        reg = self._region(config_args={"wrap": [ proxy ]}) 
+        for i in xrange(10):
+            reg.set(i,True)
+            
+        # make sure 1 was set, but 5 was not
+        eq_(reg.get(5),NO_VALUE)
+        eq_(reg.get(1),True)