Anonymous avatar Anonymous committed cec6ab8

* file backend no longer squashes unpickling errors. This was inconsistent
behavior versus all the other backends.
* invalidate_corrupt flag on Session now emits a warning. (#52)

Comments (0)

Files changed (7)

 * cache decorators @cache.cache(), @cache_region() won't include first
   argument named 'self' or 'cls' as part of the cache key.  This allows
   reasonably safe usage for methods as well as functions.  (#55)
+* file backend no longer squashes unpickling errors.   This was inconsistent
+  behavior versus all the other backends.
+* invalidate_corrupt flag on Session now emits a warning. (#52)
 
 Release 1.5.4 (6/16/2010)
 =========================

beaker/container.py

     def do_open(self, flags, replace):
         if not replace and self.file_exists(self.file):
             fh = open(self.file, 'rb')
-            try:
-                self.hash = cPickle.load(fh)
-            except (IOError, OSError, EOFError, 
-                    cPickle.PickleError, ValueError):
-                pass
+            self.hash = cPickle.load(fh)
             fh.close()
 
         self.flags = flags

beaker/exceptions.py

     pass
 
 
+class BeakerWarning(RuntimeWarning):
+    """Issued at runtime."""
+
 class CreationAbortedError(Exception):
     """Deprecated."""
 

beaker/session.py

 from datetime import datetime, timedelta
 
 from beaker.crypto import hmac as HMAC, hmac_sha1 as SHA1, md5
-from beaker.util import pickle, py3k
-
-from beaker import crypto
+from beaker import crypto, util
 from beaker.cache import clsmap
 from beaker.exceptions import BeakerException, InvalidCryptoBackendError
 from base64 import b64encode, b64decode
         else:
             try:
                 self.load()
-            except:
+            except Exception, e:
                 if invalidate_corrupt:
+                    util.warn(
+                        "Invalidating corrupt session %s; "
+                        "error was: %s.  Set invalidate_corrupt=False "
+                        "to propagate this exception." % (self.id, e))
                     self.invalidate()
                 else:
                     raise
                     random.random(),
                     getpid()
                 ) 
-        if py3k:
+        if util.py3k:
             self.id = md5(
                             md5(
                                 id_str.encode('ascii')
             nonce = b64encode(os.urandom(40))[:8]
             encrypt_key = crypto.generateCryptoKeys(self.encrypt_key,
                                              self.validate_key + nonce, 1)
-            data = pickle.dumps(self.copy(), 2)
+            data = util.pickle.dumps(self.copy(), 2)
             return nonce + b64encode(crypto.aesEncrypt(data, encrypt_key))
         else:
-            data = pickle.dumps(self.copy(), 2)
+            data = util.pickle.dumps(self.copy(), 2)
             return b64encode(data)
 
     def _decrypt_data(self):
                                              self.validate_key + nonce, 1)
             payload = b64decode(self.cookie[self.key].value[8:])
             data = crypto.aesDecrypt(payload, encrypt_key)
-            return pickle.loads(data)
+            return util.pickle.loads(data)
         else:
             data = b64decode(self.cookie[self.key].value)
-            return pickle.loads(data)
+            return util.pickle.loads(data)
 
     def _make_id(self):
         return md5(md5(
     import cPickle as pickle
 
 from beaker.converters import asbool
+from beaker import exceptions
 from threading import local as _tlocal
 
 
         return function_named(maybe, fn_name)
     return decorate
 
+def assert_raises(except_cls, callable_, *args, **kw):
+    """Assert the given exception is raised by the given function + arguments."""
+
+    try:
+        callable_(*args, **kw)
+        success = False
+    except except_cls, e:
+        success = True
+ 
+    # assert outside the block so it works for AssertionError too !
+    assert success, "Callable did not raise an exception"
+
 def verify_directory(dir):
     """verifies and creates a directory.  tries to
     ignore collisions with other threads and processes."""
 
     return inspect.getargspec(func)[0][0] in ('self', 'cls')
 
+def warn(msg, stacklevel=3):
+    """Issue a warning."""
+    if isinstance(msg, basestring):
+        warnings.warn(msg, exceptions.BeakerWarning, stacklevel=stacklevel)
+    else:
+        warnings.warn(msg, stacklevel=stacklevel)
+
 def deprecated(message):
     def wrapper(fn):
         def deprecated_method(*args, **kargs):

tests/test_cache_decorator.py

 
 import beaker.cache as cache
 from beaker.cache import CacheManager, cache_region, region_invalidate
-from beaker.util import parse_cache_config_options
+from beaker import util
 
 defaults = {'cache.data_dir':'./cache', 'cache.type':'dbm', 'cache.expire': 2}
 
 def make_cache_obj(**kwargs):
     opts = defaults.copy()
     opts.update(kwargs)
-    cache = CacheManager(**parse_cache_config_options(opts))
+    cache = CacheManager(**util.parse_cache_config_options(opts))
     return cache
 
 def make_cached_func(**opts):
     x = Foo().go(1, 2)
     y = go(1, 2)
 
-    assert cache.get_cache('test_cache_decorator.go').get('method 1 2') == x
-    assert cache.get_cache('test_cache_decorator.go').get('standalone 1 2') == y
+    ns = go._arg_namespace
+    assert cache.get_cache(ns).get('method 1 2') == x
+    assert cache.get_cache(ns).get('standalone 1 2') == y
+
+def test_func_namespace():
+    def go(x, y):
+        return "hi standalone"
+
+    assert util.func_namespace(go).endswith('test_cache_decorator.go')
 
 def test_class_key_region():
     opts = {}
 
     x = Foo().go(1, 2)
     y = go(1, 2)
-
-    assert cache.get_cache_region('test_cache_decorator.go', 'short_term').get('method 1 2') == x
-    assert cache.get_cache_region('test_cache_decorator.go', 'short_term').get('standalone 1 2') == y
+    ns = go._arg_namespace
+    assert cache.get_cache_region(ns, 'short_term').get('method 1 2') == x
+    assert cache.get_cache_region(ns, 'short_term').get('standalone 1 2') == y
 
 def test_classmethod_key_region():
     opts = {}
             return "hi"
 
     x = Foo.go(1, 2)
-    assert cache.get_cache_region('test_cache_decorator.go', 'short_term').get('method 1 2') == x
+    ns = Foo.go._arg_namespace
+    assert cache.get_cache_region(ns, 'short_term').get('method 1 2') == x
 
 def test_class_key_region_invalidate():
     opts = {}

tests/test_session.py

 import time
 
 from beaker.session import Session
+from beaker import util
 
 
 def get_session(**kwargs):
 def test_file_based_replace_optimization():
     """Test the file-based backend with session, 
     which includes the 'replace' optimization.
-    
+
     """
 
     session = get_session(use_cookies=False, type='file', 
     session.namespace.do_open('r', False)
     assert 'test' not in session.namespace
     session.namespace.do_close()
+
+
+def test_invalidate_corrupt():
+    session = get_session(use_cookies=False, type='file', 
+                            data_dir='./cache')
+    session['foo'] = 'bar'
+    session.save()
+
+    f = open(session.namespace.file, 'w')
+    f.write("crap")
+    f.close()
+
+    util.assert_raises(
+        util.pickle.UnpicklingError,
+        get_session,
+        use_cookies=False, type='file', 
+                data_dir='./cache', id=session.id
+    )
+
+    session = get_session(use_cookies=False, type='file', 
+                            invalidate_corrupt=True,
+                            data_dir='./cache', id=session.id)
+    assert "foo" not in dict(session)
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.