| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 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) |
|---|