Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import collections 

2import re 

3 

4from . import compat 

5 

6 

7def coerce_string_conf(d): 

8 result = {} 

9 for k, v in d.items(): 

10 if not isinstance(v, compat.string_types): 

11 result[k] = v 

12 continue 

13 

14 v = v.strip() 

15 if re.match(r"^[-+]?\d+$", v): 

16 result[k] = int(v) 

17 elif re.match(r"^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?$", v): 

18 result[k] = float(v) 

19 elif v.lower() in ("false", "true"): 

20 result[k] = v.lower() == "true" 

21 elif v == "None": 

22 result[k] = None 

23 else: 

24 result[k] = v 

25 return result 

26 

27 

28class PluginLoader(object): 

29 def __init__(self, group): 

30 self.group = group 

31 self.impls = {} 

32 

33 def load(self, name): 

34 if name in self.impls: 

35 return self.impls[name]() 

36 else: # pragma NO COVERAGE 

37 import pkg_resources 

38 

39 for impl in pkg_resources.iter_entry_points(self.group, name): 

40 self.impls[name] = impl.load 

41 return impl.load() 

42 else: 

43 raise self.NotFound( 

44 "Can't load plugin %s %s" % (self.group, name) 

45 ) 

46 

47 def register(self, name, modulepath, objname): 

48 def load(): 

49 mod = __import__(modulepath, fromlist=[objname]) 

50 return getattr(mod, objname) 

51 

52 self.impls[name] = load 

53 

54 class NotFound(Exception): 

55 """The specified plugin could not be found.""" 

56 

57 

58class memoized_property(object): 

59 """A read-only @property that is only evaluated once.""" 

60 

61 def __init__(self, fget, doc=None): 

62 self.fget = fget 

63 self.__doc__ = doc or fget.__doc__ 

64 self.__name__ = fget.__name__ 

65 

66 def __get__(self, obj, cls): 

67 if obj is None: 

68 return self 

69 obj.__dict__[self.__name__] = result = self.fget(obj) 

70 return result 

71 

72 

73def to_list(x, default=None): 

74 """Coerce to a list.""" 

75 if x is None: 

76 return default 

77 if not isinstance(x, (list, tuple)): 

78 return [x] 

79 else: 

80 return x 

81 

82 

83class KeyReentrantMutex(object): 

84 def __init__(self, key, mutex, keys): 

85 self.key = key 

86 self.mutex = mutex 

87 self.keys = keys 

88 

89 @classmethod 

90 def factory(cls, mutex): 

91 # this collection holds zero or one 

92 # thread idents as the key; a set of 

93 # keynames held as the value. 

94 keystore = collections.defaultdict(set) 

95 

96 def fac(key): 

97 return KeyReentrantMutex(key, mutex, keystore) 

98 

99 return fac 

100 

101 def acquire(self, wait=True): 

102 current_thread = compat.threading.current_thread().ident 

103 keys = self.keys.get(current_thread) 

104 if keys is not None and self.key not in keys: 

105 # current lockholder, new key. add it in 

106 keys.add(self.key) 

107 return True 

108 elif self.mutex.acquire(wait=wait): 

109 # after acquire, create new set and add our key 

110 self.keys[current_thread].add(self.key) 

111 return True 

112 else: 

113 return False 

114 

115 def release(self): 

116 current_thread = compat.threading.current_thread().ident 

117 keys = self.keys.get(current_thread) 

118 assert keys is not None, "this thread didn't do the acquire" 

119 assert self.key in keys, "No acquire held for key '%s'" % self.key 

120 keys.remove(self.key) 

121 if not keys: 

122 # when list of keys empty, remove 

123 # the thread ident and unlock. 

124 del self.keys[current_thread] 

125 self.mutex.release()