Index: third_party/google-endpoints/dogpile/util/langhelpers.py |
diff --git a/third_party/google-endpoints/dogpile/util/langhelpers.py b/third_party/google-endpoints/dogpile/util/langhelpers.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2d34a2cc774e1d573dfadf862f39de82c8a4fb43 |
--- /dev/null |
+++ b/third_party/google-endpoints/dogpile/util/langhelpers.py |
@@ -0,0 +1,120 @@ |
+import re |
+import collections |
+from . import compat |
+ |
+ |
+def coerce_string_conf(d): |
+ result = {} |
+ for k, v in d.items(): |
+ if not isinstance(v, compat.string_types): |
+ result[k] = v |
+ continue |
+ |
+ v = v.strip() |
+ if re.match(r'^[-+]?\d+$', v): |
+ result[k] = int(v) |
+ elif re.match(r'^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?$', v): |
+ result[k] = float(v) |
+ elif v.lower() in ('false', 'true'): |
+ result[k] = v.lower() == 'true' |
+ elif v == 'None': |
+ result[k] = None |
+ else: |
+ result[k] = v |
+ return result |
+ |
+ |
+class PluginLoader(object): |
+ def __init__(self, group): |
+ self.group = group |
+ self.impls = {} |
+ |
+ def load(self, name): |
+ if name in self.impls: |
+ return self.impls[name]() |
+ else: # pragma NO COVERAGE |
+ import pkg_resources |
+ for impl in pkg_resources.iter_entry_points( |
+ self.group, name): |
+ self.impls[name] = impl.load |
+ return impl.load() |
+ else: |
+ raise Exception( |
+ "Can't load plugin %s %s" % |
+ (self.group, name)) |
+ |
+ def register(self, name, modulepath, objname): |
+ def load(): |
+ mod = __import__(modulepath, fromlist=[objname]) |
+ return getattr(mod, objname) |
+ self.impls[name] = load |
+ |
+ |
+class memoized_property(object): |
+ """A read-only @property that is only evaluated once.""" |
+ def __init__(self, fget, doc=None): |
+ self.fget = fget |
+ self.__doc__ = doc or fget.__doc__ |
+ self.__name__ = fget.__name__ |
+ |
+ def __get__(self, obj, cls): |
+ if obj is None: |
+ return self |
+ obj.__dict__[self.__name__] = result = self.fget(obj) |
+ return result |
+ |
+ |
+def to_list(x, default=None): |
+ """Coerce to a list.""" |
+ if x is None: |
+ return default |
+ if not isinstance(x, (list, tuple)): |
+ return [x] |
+ else: |
+ return x |
+ |
+ |
+class KeyReentrantMutex(object): |
+ |
+ def __init__(self, key, mutex, keys): |
+ self.key = key |
+ self.mutex = mutex |
+ self.keys = keys |
+ |
+ @classmethod |
+ def factory(cls, mutex): |
+ # this collection holds zero or one |
+ # thread idents as the key; a set of |
+ # keynames held as the value. |
+ keystore = collections.defaultdict(set) |
+ |
+ def fac(key): |
+ return KeyReentrantMutex(key, mutex, keystore) |
+ return fac |
+ |
+ def acquire(self, wait=True): |
+ current_thread = compat.threading.current_thread().ident |
+ keys = self.keys.get(current_thread) |
+ if keys is not None and \ |
+ self.key not in keys: |
+ # current lockholder, new key. add it in |
+ keys.add(self.key) |
+ return True |
+ elif self.mutex.acquire(wait=wait): |
+ # after acquire, create new set and add our key |
+ self.keys[current_thread].add(self.key) |
+ return True |
+ else: |
+ return False |
+ |
+ def release(self): |
+ current_thread = compat.threading.current_thread().ident |
+ keys = self.keys.get(current_thread) |
+ assert keys is not None, "this thread didn't do the acquire" |
+ assert self.key in keys, "No acquire held for key '%s'" % self.key |
+ keys.remove(self.key) |
+ if not keys: |
+ # when list of keys empty, remove |
+ # the thread ident and unlock. |
+ del self.keys[current_thread] |
+ self.mutex.release() |