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

1############################################################################## 

2# 

3# Copyright (c) 2005 Zope Foundation and Contributors. 

4# All Rights Reserved. 

5# 

6# This software is subject to the provisions of the Zope Public License, 

7# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. 

8# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 

9# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 

10# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 

11# FOR A PARTICULAR PURPOSE. 

12# 

13############################################################################## 

14"""Deprecation Support 

15 

16This module provides utilities to ease the development of backward-compatible 

17code. 

18""" 

19__docformat__ = "reStructuredText" 

20import sys 

21import types 

22import warnings 

23 

24str_and_sequence_types = (str if str is not bytes else basestring, list, tuple) 

25 

26class ShowSwitch(object): 

27 """Simple stack-based switch.""" 

28 

29 def __init__(self): 

30 self.stack = [] 

31 

32 def on(self): 

33 self.stack.pop() 

34 

35 def off(self): 

36 self.stack.append(False) 

37 

38 def reset(self): 

39 self.stack = [] 

40 

41 def __call__(self): 

42 return self.stack == [] 

43 

44 def __repr__(self): 

45 return '<ShowSwitch %s>' %(self() and 'on' or 'off') 

46 

47 

48# This attribute can be used to temporarly deactivate deprecation 

49# warnings, so that backward-compatibility code can import other 

50# backward-compatiblity components without warnings being produced. 

51__show__ = ShowSwitch() 

52 

53class Suppressor(object): 

54 

55 def __enter__(self): 

56 __show__.off() 

57 

58 def __exit__(self, *ignored): 

59 __show__.on() 

60 

61ogetattr = object.__getattribute__ 

62class DeprecationProxy(object): 

63 

64 def __init__(self, module): 

65 self.__original_module = module 

66 self.__deprecated = {} 

67 

68 def deprecate(self, names, message, cls=DeprecationWarning): 

69 """Deprecate the given names.""" 

70 if not isinstance(names, (tuple, list)): 

71 names = (names,) 

72 for name in names: 

73 self.__deprecated[name] = (message, cls) 

74 

75 def __getattribute__(self, name): 

76 if name == 'deprecate' or name.startswith('_DeprecationProxy__'): 

77 return ogetattr(self, name) 

78 

79 if name == '__class__': 

80 return types.ModuleType 

81 

82 if name in ogetattr(self, '_DeprecationProxy__deprecated'): 

83 if __show__(): 

84 msg, cls = self.__deprecated[name] 

85 warnings.warn(name + ': ' + msg, cls, 2) 

86 

87 return getattr(ogetattr(self, '_DeprecationProxy__original_module'), 

88 name) 

89 

90 def __setattr__(self, name, value): 

91 if name.startswith('_DeprecationProxy__'): 

92 return object.__setattr__(self, name, value) 

93 

94 setattr(self.__original_module, name, value) 

95 

96 def __delattr__(self, name): 

97 if name.startswith('_DeprecationProxy__'): 

98 return object.__delattr__(self, name) 

99 

100 delattr(self.__original_module, name) 

101 

102class DeprecatedModule(object): 

103 

104 def __init__(self, module, msg, cls=DeprecationWarning): 

105 self.__original_module = module 

106 self.__msg = msg 

107 self.__cls = cls 

108 

109 def __getattribute__(self, name): 

110 if name.startswith('_DeprecatedModule__'): 

111 return ogetattr(self, name) 

112 

113 if name == '__class__': 

114 return types.ModuleType 

115 

116 if __show__(): 

117 warnings.warn(self.__msg, self.__cls, 2) 

118 

119 return getattr(ogetattr(self, '_DeprecatedModule__original_module'), 

120 name) 

121 

122 def __setattr__(self, name, value): 

123 if name.startswith('_DeprecatedModule__'): 

124 return object.__setattr__(self, name, value) 

125 setattr(self.__original_module, name, value) 

126 

127 def __delattr__(self, name): 

128 if name.startswith('_DeprecatedModule__'): 

129 return object.__delattr__(self, name) 

130 delattr(self.__original_module, name) 

131 

132class DeprecatedGetProperty(object): 

133 

134 def __init__(self, prop, message, cls=DeprecationWarning): 

135 self.message = message 

136 self.prop = prop 

137 self.cls = cls 

138 

139 def __get__(self, inst, klass): 

140 if __show__(): 

141 warnings.warn(self.message, self.cls, 2) 

142 return self.prop.__get__(inst, klass) 

143 

144class DeprecatedGetSetProperty(DeprecatedGetProperty): 

145 

146 def __set__(self, inst, prop): 

147 if __show__(): 

148 warnings.warn(self.message, self.cls, 2) 

149 self.prop.__set__(inst, prop) 

150 

151class DeprecatedGetSetDeleteProperty(DeprecatedGetSetProperty): 

152 

153 def __delete__(self, inst): 

154 if __show__(): 

155 warnings.warn(self.message, self.cls, 2) 

156 self.prop.__delete__(inst) 

157 

158def DeprecatedMethod(method, message, cls=DeprecationWarning): 

159 

160 def deprecated_method(*args, **kw): 

161 if __show__(): 

162 warnings.warn(message, cls, 2) 

163 return method(*args, **kw) 

164 

165 return deprecated_method 

166 

167def deprecated(specifier, message, cls=DeprecationWarning): 

168 """Deprecate the given names.""" 

169 

170 # A string specifier (or list of strings) means we're called 

171 # top-level in a module and are to deprecate things inside this 

172 # module 

173 if isinstance(specifier, str_and_sequence_types): 

174 globals = sys._getframe(1).f_globals 

175 modname = globals['__name__'] 

176 

177 if not isinstance(sys.modules[modname], DeprecationProxy): 

178 sys.modules[modname] = DeprecationProxy(sys.modules[modname]) 

179 sys.modules[modname].deprecate(specifier, message, cls) 

180 

181 

182 # Anything else can mean the specifier is a function/method, 

183 # module, or just an attribute of a class 

184 elif isinstance(specifier, types.FunctionType): 

185 return DeprecatedMethod(specifier, message, cls) 

186 elif isinstance(specifier, types.ModuleType): 

187 return DeprecatedModule(specifier, message, cls) 

188 else: 

189 prop = specifier 

190 if hasattr(prop, '__get__') and hasattr(prop, '__set__') and \ 

191 hasattr(prop, '__delete__'): 

192 return DeprecatedGetSetDeleteProperty(prop, message, cls) 

193 elif hasattr(prop, '__get__') and hasattr(prop, '__set__'): 

194 return DeprecatedGetSetProperty(prop, message, cls) 

195 elif hasattr(prop, '__get__'): 

196 return DeprecatedGetProperty(prop, message, cls) 

197 

198class deprecate(object): 

199 """Deprecation decorator""" 

200 

201 def __init__(self, msg, cls=DeprecationWarning): 

202 self.msg = msg 

203 self.cls = cls 

204 

205 def __call__(self, func): 

206 return DeprecatedMethod(func, self.msg, self.cls) 

207 

208def moved(to_location, unsupported_in=None, cls=DeprecationWarning): 

209 old = sys._getframe(1).f_globals['__name__'] 

210 message = '%s has moved to %s.' % (old, to_location) 

211 if unsupported_in: 

212 message += " Import of %s will become unsupported in %s" % ( 

213 old, unsupported_in) 

214 

215 warnings.warn(message, cls, 3) 

216 __import__(to_location) 

217 

218 fromdict = sys.modules[to_location].__dict__ 

219 tomod = sys.modules[old] 

220 tomod.__doc__ = message 

221 

222 for name, v in fromdict.items(): 

223 if name not in tomod.__dict__: 

224 setattr(tomod, name, v)