Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/SQLAlchemy-1.3.25.dev0-py3.11-linux-x86_64.egg/sqlalchemy/util/deprecations.py: 78%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

109 statements  

1# util/deprecations.py 

2# Copyright (C) 2005-2021 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: http://www.opensource.org/licenses/mit-license.php 

7 

8"""Helpers related to deprecation of functions, methods, classes, other 

9functionality.""" 

10 

11import re 

12import warnings 

13 

14from . import compat 

15from .langhelpers import _hash_limit_string 

16from .langhelpers import decorator 

17from .langhelpers import inject_docstring_text 

18from .langhelpers import inject_param_text 

19from .. import exc 

20 

21 

22def warn_deprecated(msg, stacklevel=3): 

23 warnings.warn(msg, exc.SADeprecationWarning, stacklevel=stacklevel) 

24 

25 

26def warn_deprecated_limited(msg, args, stacklevel=3): 

27 """Issue a deprecation warning with a parameterized string, 

28 limiting the number of registrations. 

29 

30 """ 

31 if args: 

32 msg = _hash_limit_string(msg, 10, args) 

33 warnings.warn(msg, exc.SADeprecationWarning, stacklevel) 

34 

35 

36def warn_pending_deprecation(msg, stacklevel=3): 

37 warnings.warn(msg, exc.SAPendingDeprecationWarning, stacklevel=stacklevel) 

38 

39 

40def deprecated_cls(version, message, constructor="__init__"): 

41 header = ".. deprecated:: %s %s" % (version, (message or "")) 

42 

43 def decorate(cls): 

44 return _decorate_cls_with_warning( 

45 cls, 

46 constructor, 

47 exc.SADeprecationWarning, 

48 message % dict(func=constructor), 

49 header, 

50 ) 

51 

52 return decorate 

53 

54 

55def deprecated(version, message=None, add_deprecation_to_docstring=True): 

56 """Decorates a function and issues a deprecation warning on use. 

57 

58 :param version: 

59 Issue version in the warning. 

60 

61 :param message: 

62 If provided, issue message in the warning. A sensible default 

63 is used if not provided. 

64 

65 :param add_deprecation_to_docstring: 

66 Default True. If False, the wrapped function's __doc__ is left 

67 as-is. If True, the 'message' is prepended to the docs if 

68 provided, or sensible default if message is omitted. 

69 

70 """ 

71 

72 if add_deprecation_to_docstring: 

73 header = ".. deprecated:: %s %s" % (version, (message or "")) 

74 else: 

75 header = None 

76 

77 if message is None: 

78 message = "Call to deprecated function %(func)s" 

79 

80 def decorate(fn): 

81 return _decorate_with_warning( 

82 fn, 

83 exc.SADeprecationWarning, 

84 message % dict(func=fn.__name__), 

85 header, 

86 ) 

87 

88 return decorate 

89 

90 

91def deprecated_params(**specs): 

92 """Decorates a function to warn on use of certain parameters. 

93 

94 e.g. :: 

95 

96 @deprecated_params( 

97 weak_identity_map=( 

98 "0.7", 

99 "the :paramref:`.Session.weak_identity_map parameter " 

100 "is deprecated." 

101 ) 

102 

103 ) 

104 

105 """ 

106 

107 messages = {} 

108 for param, (version, message) in specs.items(): 

109 messages[param] = _sanitize_restructured_text(message) 

110 

111 def decorate(fn): 

112 spec = compat.inspect_getfullargspec(fn) 

113 if spec.defaults is not None: 

114 defaults = dict( 

115 zip( 

116 spec.args[(len(spec.args) - len(spec.defaults)) :], 

117 spec.defaults, 

118 ) 

119 ) 

120 check_defaults = set(defaults).intersection(messages) 

121 check_kw = set(messages).difference(defaults) 

122 else: 

123 check_defaults = () 

124 check_kw = set(messages) 

125 

126 @decorator 

127 def warned(fn, *args, **kwargs): 

128 for m in check_defaults: 

129 if kwargs[m] != defaults[m]: 

130 warnings.warn( 

131 messages[m], exc.SADeprecationWarning, stacklevel=3 

132 ) 

133 for m in check_kw: 

134 if m in kwargs: 

135 warnings.warn( 

136 messages[m], exc.SADeprecationWarning, stacklevel=3 

137 ) 

138 

139 return fn(*args, **kwargs) 

140 

141 doc = fn.__doc__ is not None and fn.__doc__ or "" 

142 if doc: 

143 doc = inject_param_text( 

144 doc, 

145 { 

146 param: ".. deprecated:: %s %s" % (version, (message or "")) 

147 for param, (version, message) in specs.items() 

148 }, 

149 ) 

150 decorated = warned(fn) 

151 decorated.__doc__ = doc 

152 return decorated 

153 

154 return decorate 

155 

156 

157def pending_deprecation( 

158 version, message=None, add_deprecation_to_docstring=True 

159): 

160 """Decorates a function and issues a pending deprecation warning on use. 

161 

162 :param version: 

163 An approximate future version at which point the pending deprecation 

164 will become deprecated. Not used in messaging. 

165 

166 :param message: 

167 If provided, issue message in the warning. A sensible default 

168 is used if not provided. 

169 

170 :param add_deprecation_to_docstring: 

171 Default True. If False, the wrapped function's __doc__ is left 

172 as-is. If True, the 'message' is prepended to the docs if 

173 provided, or sensible default if message is omitted. 

174 """ 

175 

176 if add_deprecation_to_docstring: 

177 header = ".. deprecated:: %s (pending) %s" % (version, (message or "")) 

178 else: 

179 header = None 

180 

181 if message is None: 

182 message = "Call to deprecated function %(func)s" 

183 

184 def decorate(fn): 

185 return _decorate_with_warning( 

186 fn, 

187 exc.SAPendingDeprecationWarning, 

188 message % dict(func=fn.__name__), 

189 header, 

190 ) 

191 

192 return decorate 

193 

194 

195def deprecated_option_value(parameter_value, default_value, warning_text): 

196 if parameter_value is None: 

197 return default_value 

198 else: 

199 warn_deprecated(warning_text) 

200 return parameter_value 

201 

202 

203def _sanitize_restructured_text(text): 

204 def repl(m): 

205 type_, name = m.group(1, 2) 

206 if type_ in ("func", "meth"): 

207 name += "()" 

208 return name 

209 

210 return re.sub(r"\:(\w+)\:`~?(?:_\w+)?\.?(.+?)`", repl, text) 

211 

212 

213def _decorate_cls_with_warning( 

214 cls, constructor, wtype, message, docstring_header=None 

215): 

216 doc = cls.__doc__ is not None and cls.__doc__ or "" 

217 if docstring_header is not None: 

218 docstring_header %= dict(func=constructor) 

219 

220 doc = inject_docstring_text(doc, docstring_header, 1) 

221 

222 if type(cls) is type: 

223 clsdict = dict(cls.__dict__) 

224 clsdict["__doc__"] = doc 

225 cls = type(cls.__name__, cls.__bases__, clsdict) 

226 constructor_fn = clsdict[constructor] 

227 else: 

228 cls.__doc__ = doc 

229 constructor_fn = getattr(cls, constructor) 

230 

231 setattr( 

232 cls, 

233 constructor, 

234 _decorate_with_warning(constructor_fn, wtype, message, None), 

235 ) 

236 

237 return cls 

238 

239 

240def _decorate_with_warning(func, wtype, message, docstring_header=None): 

241 """Wrap a function with a warnings.warn and augmented docstring.""" 

242 

243 message = _sanitize_restructured_text(message) 

244 

245 @decorator 

246 def warned(fn, *args, **kwargs): 

247 warnings.warn(message, wtype, stacklevel=3) 

248 return fn(*args, **kwargs) 

249 

250 doc = func.__doc__ is not None and func.__doc__ or "" 

251 if docstring_header is not None: 

252 docstring_header %= dict(func=func.__name__) 

253 

254 doc = inject_docstring_text(doc, docstring_header, 1) 

255 

256 decorated = warned(func) 

257 decorated.__doc__ = doc 

258 decorated._sa_warn = lambda: warnings.warn(message, wtype, stacklevel=3) 

259 return decorated