OLD | NEW |
(Empty) | |
| 1 import uuid |
| 2 |
| 3 #TODO: Consider expiring values after some fixed time for long-running |
| 4 #servers |
| 5 |
| 6 |
| 7 class Stash(object): |
| 8 """Key-value store for persisting data across HTTP requests. |
| 9 |
| 10 This data store specifically designed for persisting data across |
| 11 HTTP requests. It is entirely in-memory so data will not be |
| 12 persisted across server restarts. |
| 13 |
| 14 This has several unusual properties. Keys are of the form (path, |
| 15 uuid), where path is, by default, the path in the HTTP request and |
| 16 uuid is a unique id. In addition, the store is write-once, read-once, |
| 17 i.e. the value associated with a particular key cannot be changed once |
| 18 written and the read operation (called "take") is destructive. Taken togethe
r, |
| 19 these properties make it difficult for data to accidentally leak |
| 20 between different resources or different requests for the same |
| 21 resource. |
| 22 |
| 23 """ |
| 24 |
| 25 data = {} |
| 26 |
| 27 def __init__(self, default_path): |
| 28 self.default_path = default_path |
| 29 |
| 30 def put(self, key, value, path=None): |
| 31 """Place a value in the stash. |
| 32 |
| 33 :param key: A UUID to use as the data's key. |
| 34 :param value: The data to store. This can be any python object. |
| 35 :param path: The path that has access to read the data (by default |
| 36 the current request path)""" |
| 37 if path is None: |
| 38 path = self.default_path |
| 39 if path not in self.data: |
| 40 self.data[path] = PathStash(path) |
| 41 |
| 42 self.data[path][key] = value |
| 43 |
| 44 def take(self, key, path=None): |
| 45 """Remove a value from the stash and return it. |
| 46 |
| 47 :param key: A UUID to use as the data's key. |
| 48 :param path: The path that has access to read the data (by default |
| 49 the current request path)""" |
| 50 if path is None: |
| 51 path = self.default_path |
| 52 |
| 53 if path in self.data: |
| 54 value = self.data[path][key] |
| 55 else: |
| 56 value = None |
| 57 return value |
| 58 |
| 59 |
| 60 class PathStash(dict): |
| 61 def __init__(self, path): |
| 62 self.path = path |
| 63 |
| 64 def __setitem__(self, key, value): |
| 65 key = uuid.UUID(key) |
| 66 if value is None: |
| 67 raise ValueError("Stash value may not be set to None") |
| 68 if key in self: |
| 69 raise StashError("Tried to overwrite existing stash value " |
| 70 "for path %s and key %s (old value was %s, new valu
e is %s)" % |
| 71 (self.path, key, self[str(key)], value)) |
| 72 else: |
| 73 dict.__setitem__(self, key, value) |
| 74 |
| 75 def __getitem__(self, key): |
| 76 key = uuid.UUID(key) |
| 77 rv = dict.get(self, key, None) |
| 78 if rv is not None: |
| 79 del self[key] |
| 80 return rv |
| 81 |
| 82 |
| 83 class StashError(Exception): |
| 84 pass |
OLD | NEW |