OLD | NEW |
(Empty) | |
| 1 import re |
| 2 import collections |
| 3 from . import compat |
| 4 |
| 5 |
| 6 def coerce_string_conf(d): |
| 7 result = {} |
| 8 for k, v in d.items(): |
| 9 if not isinstance(v, compat.string_types): |
| 10 result[k] = v |
| 11 continue |
| 12 |
| 13 v = v.strip() |
| 14 if re.match(r'^[-+]?\d+$', v): |
| 15 result[k] = int(v) |
| 16 elif re.match(r'^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?$', v): |
| 17 result[k] = float(v) |
| 18 elif v.lower() in ('false', 'true'): |
| 19 result[k] = v.lower() == 'true' |
| 20 elif v == 'None': |
| 21 result[k] = None |
| 22 else: |
| 23 result[k] = v |
| 24 return result |
| 25 |
| 26 |
| 27 class PluginLoader(object): |
| 28 def __init__(self, group): |
| 29 self.group = group |
| 30 self.impls = {} |
| 31 |
| 32 def load(self, name): |
| 33 if name in self.impls: |
| 34 return self.impls[name]() |
| 35 else: # pragma NO COVERAGE |
| 36 import pkg_resources |
| 37 for impl in pkg_resources.iter_entry_points( |
| 38 self.group, name): |
| 39 self.impls[name] = impl.load |
| 40 return impl.load() |
| 41 else: |
| 42 raise Exception( |
| 43 "Can't load plugin %s %s" % |
| 44 (self.group, name)) |
| 45 |
| 46 def register(self, name, modulepath, objname): |
| 47 def load(): |
| 48 mod = __import__(modulepath, fromlist=[objname]) |
| 49 return getattr(mod, objname) |
| 50 self.impls[name] = load |
| 51 |
| 52 |
| 53 class memoized_property(object): |
| 54 """A read-only @property that is only evaluated once.""" |
| 55 def __init__(self, fget, doc=None): |
| 56 self.fget = fget |
| 57 self.__doc__ = doc or fget.__doc__ |
| 58 self.__name__ = fget.__name__ |
| 59 |
| 60 def __get__(self, obj, cls): |
| 61 if obj is None: |
| 62 return self |
| 63 obj.__dict__[self.__name__] = result = self.fget(obj) |
| 64 return result |
| 65 |
| 66 |
| 67 def to_list(x, default=None): |
| 68 """Coerce to a list.""" |
| 69 if x is None: |
| 70 return default |
| 71 if not isinstance(x, (list, tuple)): |
| 72 return [x] |
| 73 else: |
| 74 return x |
| 75 |
| 76 |
| 77 class KeyReentrantMutex(object): |
| 78 |
| 79 def __init__(self, key, mutex, keys): |
| 80 self.key = key |
| 81 self.mutex = mutex |
| 82 self.keys = keys |
| 83 |
| 84 @classmethod |
| 85 def factory(cls, mutex): |
| 86 # this collection holds zero or one |
| 87 # thread idents as the key; a set of |
| 88 # keynames held as the value. |
| 89 keystore = collections.defaultdict(set) |
| 90 |
| 91 def fac(key): |
| 92 return KeyReentrantMutex(key, mutex, keystore) |
| 93 return fac |
| 94 |
| 95 def acquire(self, wait=True): |
| 96 current_thread = compat.threading.current_thread().ident |
| 97 keys = self.keys.get(current_thread) |
| 98 if keys is not None and \ |
| 99 self.key not in keys: |
| 100 # current lockholder, new key. add it in |
| 101 keys.add(self.key) |
| 102 return True |
| 103 elif self.mutex.acquire(wait=wait): |
| 104 # after acquire, create new set and add our key |
| 105 self.keys[current_thread].add(self.key) |
| 106 return True |
| 107 else: |
| 108 return False |
| 109 |
| 110 def release(self): |
| 111 current_thread = compat.threading.current_thread().ident |
| 112 keys = self.keys.get(current_thread) |
| 113 assert keys is not None, "this thread didn't do the acquire" |
| 114 assert self.key in keys, "No acquire held for key '%s'" % self.key |
| 115 keys.remove(self.key) |
| 116 if not keys: |
| 117 # when list of keys empty, remove |
| 118 # the thread ident and unlock. |
| 119 del self.keys[current_thread] |
| 120 self.mutex.release() |
OLD | NEW |