root / trunk / twisted / python / deprecate.py

Revision 24931, 3.8 kB (checked in by therve, 9 months ago)

Merge fqn-3254-2

Author: therve
Reviewer: exarkun
Fixes #3254

Add function fullyQualifiedName which is able to get the name of a module,
class, method or function, and use it in the deprecation mechanism instead of
qual: this makes deprecation on method return the correct name.

Line 
1 # -*- test-case-name: twisted.python.test.test_deprecate -*-
2 # Copyright (c) 2008 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Deprecation framework for Twisted.
7
8 To mark a method or function as being deprecated do this::
9
10     def badAPI(self, first, second):
11         '''
12         Docstring for badAPI.
13         '''
14         ...
15     badAPI = deprecate(Version("Twisted", 8, 0, 0))(badAPI)
16
17 The newly-decorated badAPI will issue a warning when called. It will also have
18 a deprecation notice appended to its docstring.
19
20 See also L{Version}.
21 """
22
23
24 __all__ = [
25     'deprecated',
26     'getDeprecationWarningString',
27     'getWarningMethod',
28     'setWarningMethod',
29     ]
30
31
32 from warnings import warn
33
34 from twisted.python.versions import getVersionString
35 from twisted.python.reflect import fullyQualifiedName
36 from twisted.python.util import mergeFunctionMetadata
37
38
39 def getWarningMethod():
40     """
41     Return the warning method currently used to record deprecation warnings.
42     """
43     return warn
44
45
46
47 def setWarningMethod(newMethod):
48     """
49     Set the warning method to use to record deprecation warnings.
50
51     The callable should take message, category and stacklevel. The return
52     value is ignored.
53     """
54     global warn
55     warn = newMethod
56
57
58
59 def _getDeprecationDocstring(version):
60     return "Deprecated in %s." % getVersionString(version)
61
62
63
64 def getDeprecationWarningString(callableThing, version):
65     """
66     Return a string indicating that the callable was deprecated in the given
67     version.
68
69     @param callableThing: A callable to be deprecated.
70     @param version: The L{twisted.python.versions.Version} that the callable
71         was deprecated in.
72     @return: A string describing the deprecation.
73     """
74     return "%s was deprecated in %s" % (
75         fullyQualifiedName(callableThing), getVersionString(version))
76
77
78
79 def deprecated(version):
80     """
81     Return a decorator that marks callables as deprecated.
82
83     @type version: L{twisted.python.versions.Version}
84     @param version: The version in which the callable will be marked as
85         having been deprecated.  The decorated function will be annotated
86         with this version, having it set as its C{deprecatedVersion}
87         attribute.
88     """
89     def deprecationDecorator(function):
90         """
91         Decorator that marks C{function} as deprecated.
92         """
93         warningString = getDeprecationWarningString(function, version)
94
95         def deprecatedFunction(*args, **kwargs):
96             warn(
97                 warningString,
98                 DeprecationWarning,
99                 stacklevel=2)
100             return function(*args, **kwargs)
101
102         deprecatedFunction = mergeFunctionMetadata(
103             function, deprecatedFunction)
104         _appendToDocstring(deprecatedFunction,
105                            _getDeprecationDocstring(version))
106         deprecatedFunction.deprecatedVersion = version
107         return deprecatedFunction
108
109     return deprecationDecorator
110
111
112
113 def _appendToDocstring(thingWithDoc, textToAppend):
114     """
115     Append the given text to the docstring of C{thingWithDoc}.
116
117     If C{thingWithDoc} has no docstring, then the text just replaces the
118     docstring. If it has a single-line docstring then it appends a blank line
119     and the message text. If it has a multi-line docstring, then in appends a
120     blank line a the message text, and also does the indentation correctly.
121     """
122     if thingWithDoc.__doc__:
123         docstringLines = thingWithDoc.__doc__.splitlines()
124     else:
125         docstringLines = []
126
127     if len(docstringLines) == 0:
128         docstringLines.append(textToAppend)
129     elif len(docstringLines) == 1:
130         docstringLines.extend(['', textToAppend, ''])
131     else:
132         spaces = docstringLines.pop()
133         docstringLines.extend(['',
134                                spaces + textToAppend,
135                                spaces])
136     thingWithDoc.__doc__ = '\n'.join(docstringLines)
Note: See TracBrowser for help on using the browser.