Decorators in The Python Standard Lib (@deprecated Specifically)
Decorators in The Python Standard Lib (@deprecated Specifically)
1. Products
1.
hari haran
31
, 31 reputation
●11 silver badge●55 bronze badges
2.
3.
4.
5.
6.
1. Home
2.
1. PUBLIC
2. Stack Overflow
3. Tags
4. Users
5. Jobs
3.
1. TEAMS
What’s this?
2.
Free 30 Day Trial
Additional question: are there standard decorators in the standard library at all ?
python decorator
Stefano Borini
117k7676 gold badges265265 silver badges386386 bronze badges
• 13
now there is a deprecation package – muon Nov 1 '17 at 21:13
• 10
I understand the ways to do it, but came here for some insight on why it's not in the std lib (as I assume is
the case of the OP) and don't see a good answer to the actual question – SwimBikeRun Apr 1 '19 at 14:57
• 3
Why does it happen so often that questions get dozens of answers that don't even attempt to answer the
question, and actively ignore things like "I'm aware of recipes"? It's maddening! – Catskul May 2 '19 at
16:46
• 1
@Catskul because of fake internet points. – Stefano Borini May 2 '19 at 19:07
• You can use the Deprecated Library. – Laurent LAPORTE May 20 '19 at 20:21
add a comment
7 Answers
ActiveOldestVotes
57
Here's some snippet, modified from those cited by Leandro:
import warnings
import functools
def deprecated(func):
"""This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used."""
@functools.wraps(func)
def new_func(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning) # turn off filter
warnings.warn("Call to deprecated function {}.".format(func.__name__),
category=DeprecationWarning,
stacklevel=2)
warnings.simplefilter('default', DeprecationWarning) # reset filter
return func(*args, **kwargs)
return new_func
# Examples
@deprecated
def some_old_function(x, y):
return x + y
class SomeClass:
@deprecated
def some_old_method(self, x, y):
return x + y
Because in some interpreters the first solution exposed (without filter handling) may result in a
warning suppression.
endolith
18.3k2323 gold badges102102 silver badges169169 bronze badges
answered May 15 '15 at 7:24
Patrizio Bertoni
1,9352121 silver badges3333 bronze badges
• 13
Why not use functools.wraps rather than setting the name and doc like that? – Maximilian Aug 6 '15 at
14:40
• 1
@Maximilian: Edited to add that, to save future copy-pasters of this code from doing it wrong
too – Eric Jun 28 '16 at 3:59
• 16
I do not like side effect (turning the filter on / off). It's not the job of the decorator to decide
this. – Kentzo Apr 18 '17 at 17:48
• 1
Turning the filter on and off may trigger bugs.python.org/issue29672 – gerrit Jul 7 '17 at 16:13
• 3
doesn't answer the actual question. – Catskul May 2 '19 at 16:41
add a comment
Report this ad
40
Here is another solution:
This decorator (a decorator factory in fact) allow you to give a reason message. It is also more
useful to help the developer to diagnose the problem by giving the source filename and line
number.
EDIT: This code use Zero's recommendation: it replace warnings.warn_explicit line
by warnings.warn(msg, category=DeprecationWarning, stacklevel=2), which prints the
function call site rather than the function definition site. It makes debugging easier.
EDIT2: This version allow the developper to specify an optional "reason" message.
import functools
import inspect
import warnings
def deprecated(reason):
"""
This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used.
"""
if isinstance(reason, string_types):
def decorator(func1):
if inspect.isclass(func1):
fmt1 = "Call to deprecated class {name} ({reason})."
else:
fmt1 = "Call to deprecated function {name} ({reason})."
@functools.wraps(func1)
def new_func1(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning)
warnings.warn(
fmt1.format(name=func1.__name__, reason=reason),
category=DeprecationWarning,
stacklevel=2
)
warnings.simplefilter('default', DeprecationWarning)
return func1(*args, **kwargs)
return new_func1
return decorator
if inspect.isclass(func2):
fmt2 = "Call to deprecated class {name}."
else:
fmt2 = "Call to deprecated function {name}."
@functools.wraps(func2)
def new_func2(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning)
warnings.warn(
fmt2.format(name=func2.__name__),
category=DeprecationWarning,
stacklevel=2
)
warnings.simplefilter('default', DeprecationWarning)
return func2(*args, **kwargs)
return new_func2
else:
raise TypeError(repr(type(reason)))
You can use this decorator for functions, methods and classes.
Here is a simple example:
class SomeClass(object):
@deprecated("use another method")
def some_old_method(self, x, y):
return x + y
some_old_function(5, 3)
SomeClass().some_old_method(8, 9)
SomeOldClass()
You'll get:
Laurent LAPORTE
16.3k33 gold badges3838 silver badges7171 bronze badges
• 6
Works, well - I prefer replacing the warn_explicit line with warnings.warn(msg,
category=DeprecationWarning, stacklevel=2) which prints the function call site rather than the
function definition site. It makes debugging easier. – Zero Nov 28 '16 at 23:24
• Hello, I would like to use your code snippet in a GPLv3-licensed library. Would you be willing to relicense
your code under GPLv3 or any more permissive license, so that I can legally do so? – gerrit Jul 7 '17 at
17:19
• @gerrit: All user contributions are licensed under Creative Commons Attribution-Share Alike. – Laurent
LAPORTE Jul 9 '17 at 10:15
• 1
@LaurentLAPORTE I know. CC-BY-SO does not permit usage within GPLv3 (because of the share-alike
bit), which is why I'm asking if you would be willing to release this code specifically additionally under a
GPL-compatible license. If not, that's fine, and I won't use your code. – gerrit Jul 9 '17 at 14:27
• 2
doesn't answer the actual question. – Catskul May 2 '19 at 16:42
add a comment
11
As muon suggested, you can install the deprecation package for this.
The deprecation library provides a deprecated decorator and a fail_if_not_removed decorator
for your tests.
Installation
pip install deprecation
Example Usage
import deprecation
@deprecation.deprecated(deprecated_in="1.0", removed_in="2.0",
current_version=__version__,
details="Use the bar function instead")
def foo():
"""Do some stuff"""
return 1
See http://deprecation.readthedocs.io/ for the full documentation.
share edit follow flag
edited Jun 10 '18 at 23:03
CrackerJack9
3,54111 gold badge2222 silver badges4646 bronze badges
answered May 16 '18 at 17:49
Stevoisiak
12.4k1414 gold badges8484 silver badges137137 bronze badges
• 3
doesn't answer the actual question. – Catskul May 2 '19 at 16:43
• Note PyCharm doesn't recognise this – c z Aug 23 '19 at 10:55
add a comment
10
I guess the reason is that Python code can't be processed statically (as it done for C++
compilers), you can't get warning about using some things before actually using it. I don't think
that it's a good idea to spam user of your script with a bunch of messages "Warning: this
developer of this script is using deprecated API".
Update: but you can create decorator which will transform original function into another. New
function will mark/check switch telling that this function was called already and will show
message only on turning switch into on state. And/or at exit it may print list of all deprecated
functions used in program.
share edit follow flag
edited Feb 21 '13 at 11:40
answered Mar 29 '10 at 7:36
ony
7,98911 gold badge2626 silver badges3939 bronze badges
• 3
And you should be able to indicate deprecation when the function is imported from the module.
Decorator would be a right tool for that. – Janusz Lenar Feb 21 '13 at 9:23
• @JanuszLenar, that warning will be show even if we don't use that deprecated function. But I guess I can
update my answer with some hint. – ony Feb 21 '13 at 11:37
add a comment
8
You can create a utils file
import warnings
def deprecated(message):
def deprecated_decorator(func):
def deprecated_func(*args, **kwargs):
warnings.warn("{} is a deprecated function. {}".format(func.__name__, message),
category=DeprecationWarning,
stacklevel=2)
warnings.simplefilter('default', DeprecationWarning)
return func(*args, **kwargs)
return deprecated_func
return deprecated_decorator
And then import the deprecation decorator as follows:
Erika Dsouza
47977 silver badges77 bronze badges
• Thanks, I'm using this to send the user to the right place instead of just showing the deprecation
message! – German Attanasio Feb 5 '18 at 22:03
• 3
doesn't answer the actual question. – Catskul May 2 '19 at 16:42
add a comment
2
UPDATE: I think is better, when we show DeprecationWarning only first time for each code
line and when we can send some message:
import inspect
import traceback
import warnings
import functools
import time
function_wrapper.last_call_source = set()
return function_wrapper
return decorator_wrapper
def my_func2():
print('bbb')
before cycle
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:45: DeprecationWarning: Function my_func is now
deprecated! You must use my_func2!
aaa
aaa
aaa
aaa
aaa
after cycle
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:47: DeprecationWarning: Function my_func is now
deprecated! You must use my_func2!
aaa
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:48: DeprecationWarning: Function my_func is now
deprecated! You must use my_func2!
aaa
C:/Users/adr-0/OneDrive/Projects/Python/test/unit1.py:49: DeprecationWarning: Function my_func is now
deprecated! You must use my_func2!
aaa
ADR
97555 silver badges1616 bronze badges
• 2
doesn't answer the actual question. – Catskul May 2 '19 at 16:43
add a comment
0
Augmenting this answer by Steven Vascellaro:
If you use Anaconda, first install deprecation package:
conda install -c conda-forge deprecation
Then paste the following on the top of the file
import deprecation
@deprecation.deprecated(deprecated_in="1.0", removed_in="2.0",
current_version=__version__,
details="Use the bar function instead")
def foo():
"""Do some stuff"""
return 1
See http://deprecation.readthedocs.io/ for the full documentation.
share edit follow flag
answered Jul 23 '18 at 4:51
omerbp
3,46733 gold badges2525 silver badges4141 bronze badges
• 3
doesn't answer the actual question. – Catskul May 2 '19 at 16:43
add a comment
Your Answer
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
• Links
• Images
• Styling/Headers
• Lists
• Blockquotes
• Code
• HTML
• Advanced help
Community wiki
Post Your Answer
Not the answer you're looking for? Browse other questions tagged python decorator or ask
your own question.
The Overflow Blog
• Podcast 235: An emotional week, and the way forward
• The Overflow #21: The way forward
Featured on Meta
•
•
Software Engineer
RodeoAmsterdam, Netherlands
RELOCATION
pythondocker
•
Software Developer
PicnicAmsterdam, Netherlands
RELOCATION
pythonpostgresql
•
Backend Developer
DolfinAmsterdam, Netherlands
REMOTERELOCATION
pythonreactjs
•
Data Engineer (Amsterdam)
ML6Amsterdam, Netherlands
pythonlinux
•
Python Software Engineer
bloomonAmsterdam, Netherlands
€65K - €75KRELOCATION
pythonphp
•
C++ Software Engineer
Flow TradersAmsterdam, Netherlands
€70K - €80KRELOCATION
gitlinux
•
Python Software Engineer (40h/wk)
ChannableUtrecht, Netherlands
pythonsql
Linked
2746
How to make a chain of function decorators?
12
Renaming of functions with preservation of backward compatibility
Related
4851
Calling an external command from Python
5692
What are metaclasses in Python?
3143
Finding the index of an item in a list
5992
Does Python have a ternary conditional operator?
2856
How to get the current time in Python
2746
How to make a chain of function decorators?
3599
Does Python have a string 'contains' substring method?
936
Creating a singleton in Python
972
How does the @property decorator work?
Question feed
https://stack
STACK OVERFLOW
• Questions
• Jobs
• Developer Jobs Directory
• Salary Calculator
• Help
• Mobile
• Disable Responsiveness
PRODUCTS
• Teams
• Talent
• Advertising
• Enterprise
COMPANY
• About
• Press
• Work Here
• Legal
• Privacy Policy
• Contact Us
STACK EXCHANGE
NETWORK
• Technology
• Life / Arts
• Culture / Recreation
• Science
• Other
• Blog
• Facebook
• Twitter
• LinkedIn
• Instagram
site design / logo © 2020 Stack Exchange Inc; user contributions licensed under cc by-sa. rev 2020.5.15.36837