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

1from statsmodels.tools.sm_exceptions import CacheWriteWarning 

2from statsmodels.compat.pandas import cache_readonly as PandasCacheReadonly 

3 

4import warnings 

5 

6__all__ = ['cache_readonly', 'cache_writable', 'deprecated_alias', 

7 'ResettableCache'] 

8 

9 

10class ResettableCache(dict): 

11 """DO NOT USE. BACKWARD COMPAT ONLY""" 

12 def __init__(self, *args, **kwargs): 

13 super(ResettableCache, self).__init__(*args, **kwargs) 

14 self.__dict__ = self 

15 

16 

17def deprecated_alias(old_name, new_name, remove_version=None, msg=None, 

18 warning=FutureWarning): 

19 """ 

20 Deprecate attribute in favor of alternative name. 

21 

22 Parameters 

23 ---------- 

24 old_name : str 

25 Old, deprecated name 

26 new_name : str 

27 New name 

28 remove_version : str, optional 

29 Version that the alias will be removed 

30 msg : str, optional 

31 Message to show. Default is 

32 `old_name` is a deprecated alias for `new_name` 

33 warning : Warning, optional 

34 Warning class to give. Default is FutureWarning. 

35 

36 Notes 

37 ----- 

38 Older or less-used classes may not conform to statsmodels naming 

39 conventions. `deprecated_alias` lets us bring them into conformance 

40 without breaking backward-compatibility. 

41 

42 Example 

43 ------- 

44 Instances of the `Foo` class have a `nvars` attribute, but it _should_ 

45 be called `neqs`: 

46 

47 class Foo(object): 

48 nvars = deprecated_alias('nvars', 'neqs') 

49 def __init__(self, neqs): 

50 self.neqs = neqs 

51 

52 >>> foo = Foo(3) 

53 >>> foo.nvars 

54 __main__:1: FutureWarning: nvars is a deprecated alias for neqs 

55 3 

56 """ 

57 

58 if msg is None: 

59 msg = '%s is a deprecated alias for %s' % (old_name, new_name) 

60 if remove_version is not None: 

61 msg += ', will be removed in version %s' % remove_version 

62 

63 def fget(self): 

64 warnings.warn(msg, warning, stacklevel=2) 

65 return getattr(self, new_name) 

66 

67 def fset(self, value): 

68 warnings.warn(msg, warning, stacklevel=2) 

69 setattr(self, new_name, value) 

70 

71 res = property(fget=fget, fset=fset) 

72 return res 

73 

74 

75class CachedAttribute(object): 

76 

77 def __init__(self, func, cachename=None): 

78 self.fget = func 

79 self.name = func.__name__ 

80 self.cachename = cachename or '_cache' 

81 

82 def __get__(self, obj, type=None): 

83 if obj is None: 

84 return self.fget 

85 # Get the cache or set a default one if needed 

86 _cachename = self.cachename 

87 _cache = getattr(obj, _cachename, None) 

88 if _cache is None: 

89 setattr(obj, _cachename, {}) 

90 _cache = getattr(obj, _cachename) 

91 # Get the name of the attribute to set and cache 

92 name = self.name 

93 _cachedval = _cache.get(name, None) 

94 if _cachedval is None: 

95 _cachedval = self.fget(obj) 

96 _cache[name] = _cachedval 

97 

98 return _cachedval 

99 

100 def __set__(self, obj, value): 

101 errmsg = "The attribute '%s' cannot be overwritten" % self.name 

102 warnings.warn(errmsg, CacheWriteWarning) 

103 

104 

105class CachedWritableAttribute(CachedAttribute): 

106 def __set__(self, obj, value): 

107 _cache = getattr(obj, self.cachename) 

108 name = self.name 

109 _cache[name] = value 

110 

111 

112class _cache_readonly(property): 

113 """ 

114 Decorator for CachedAttribute 

115 """ 

116 

117 def __init__(self, cachename=None): 

118 self.func = None 

119 self.cachename = cachename 

120 

121 def __call__(self, func): 

122 return CachedAttribute(func, 

123 cachename=self.cachename) 

124 

125 

126class cache_writable(_cache_readonly): 

127 """ 

128 Decorator for CachedWritableAttribute 

129 """ 

130 def __call__(self, func): 

131 return CachedWritableAttribute(func, 

132 cachename=self.cachename) 

133 

134 

135# Use pandas since it works with docs correctly 

136cache_readonly = PandasCacheReadonly 

137# cached_value and cached_data behave identically to cache_readonly, but 

138# are used by `remove_data` to 

139# a) identify array-like attributes to remove (cached_data) 

140# b) make sure certain values are evaluated before caching (cached_value) 

141# TODO: Disabled since the subclasses break doc strings 

142# class cached_data(PandasCacheReadonly): 

143# pass 

144 

145cached_data = PandasCacheReadonly 

146 

147# class cached_value(PandasCacheReadonly): 

148# pass 

149 

150cached_value = PandasCacheReadonly 

151 

152 

153def nottest(fn): 

154 fn.__test__ = False 

155 return fn