0% found this document useful (0 votes)
87 views

Decorators in The Python Standard Lib (@deprecated Specifically)

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
87 views

Decorators in The Python Standard Lib (@deprecated Specifically)

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Stack Overflow

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

decorators in the python standard lib


(@deprecated specifically)
Ask Question
Asked 10 years, 1 month ago
Active 2 days ago
Viewed 60k times
Report this ad
119
26
I need to mark routines as deprecated, but apparently there's no standard library decorator for
deprecation. I am aware of recipes for it and the warnings module, but my question is: why is
there no standard library decorator for this (common) task ?

Additional question: are there standard decorators in the standard library at all ?

python decorator

share edit follow flag


edited May 16 '18 at 18:00
Stevoisiak
12.4k1414 gold badges8484 silver badges137137 bronze badges
asked Mar 29 '10 at 7:14

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.

share edit follow flag


edited Jan 28 '18 at 16:04

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

string_types = (type(b''), type(u''))

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):

# The @deprecated is used with a 'reason'.


#
# .. code-block:: python
#
# @deprecated("please, use another function")
# def old_function(x, y):
# pass

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

elif inspect.isclass(reason) or inspect.isfunction(reason):

# The @deprecated is used without any 'reason'.


#
# .. code-block:: python
#
# @deprecated
# def old_function(x, y):
# pass
func2 = reason

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:

@deprecated("use another function")


def some_old_function(x, y):
return x + y

class SomeClass(object):
@deprecated("use another method")
def some_old_method(self, x, y):
return x + y

@deprecated("use another class")


class SomeOldClass(object):
pass

some_old_function(5, 3)
SomeClass().some_old_method(8, 9)
SomeOldClass()
You'll get:

deprecated_example.py:59: DeprecationWarning: Call to deprecated function or method some_old_function


(use another function).
some_old_function(5, 3)
deprecated_example.py:60: DeprecationWarning: Call to deprecated function or method some_old_method
(use another method).
SomeClass().some_old_method(8, 9)
deprecated_example.py:61: DeprecationWarning: Call to deprecated class SomeOldClass (use another class).
SomeOldClass()
EDIT3: This decorator is now part of the Deprecated library:
• Python package index (PyPi)
• GitHub website
• Read The Docs
• Twitter
New stable release v1.2.10 🎉

share edit follow flag


edited 2 days ago
answered Oct 28 '16 at 8:55

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:

from .utils import deprecated

@deprecated("Use method yyy instead")


def some_method()"
pass
share edit follow flag
answered Feb 5 '18 at 21:50

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

def deprecated(message: str = ''):


"""
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 first time and filter is set for show DeprecationWarning.
"""
def decorator_wrapper(func):
@functools.wraps(func)
def function_wrapper(*args, **kwargs):
current_call_source = '|'.join(traceback.format_stack(inspect.currentframe()))
if current_call_source not in function_wrapper.last_call_source:
warnings.warn("Function {} is now deprecated! {}".format(func.__name__, message),
category=DeprecationWarning, stacklevel=2)
function_wrapper.last_call_source.add(current_call_source)

return func(*args, **kwargs)

function_wrapper.last_call_source = set()

return function_wrapper
return decorator_wrapper

@deprecated('You must use my_func2!')


def my_func():
time.sleep(.1)
print('aaa')
time.sleep(.1)

def my_func2():
print('bbb')

warnings.simplefilter('always', DeprecationWarning) # turn off filter


print('before cycle')
for i in range(5):
my_func()
print('after cycle')
my_func()
my_func()
my_func()
Result:

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

Process finished with exit code 0


We can just click on the warning path and go to the line in PyCharm.
share edit follow flag
edited Nov 30 '16 at 23:09
answered Nov 30 '16 at 22:34

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

Creative Commons Licensing UI and Data Updates


Meta escalation/response process update (March-April 2020 test results, next…



Threshold experiment results: closing, editing and reopening all become more…

It's time to reward the duplicate finders


Report this ad
Jobs near you

Backend Engineer
Innovation Research LabsAmsterdam, Netherlands
€50K - €95KREMOTERELOCATION
pythonsecurity


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

View more jobs on Stack Overflow

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?

Hot Network Questions


▪ Was Arthur C Clarke deliberately quoting Ray Bradbury in the Novel of 2001: A Space Odyssey
▪ Minimize edges of a directed unweighted graph
▪ Why is the output of a filter considered 70.7% of input while determining the cutoff frequency?
▪ How to play this double sharp note
▪ Breaking Bad script and actual episode are totally similar, is that usual?
▪ How to track turn-taking in Catan
▪ Is it possible to detect gravitational lensing behind the Moon?
▪ What was a "Windows protection error"?
▪ How to make all digits oldstyle?
▪ Can player characters get turned into zombies? And if they can, what changes?
▪ Why were optical drives not used as secondary storage instead of magnetic drives?
▪ 1 to at least 200 Latin list cardinal numbers
▪ Are gas stoves preferred in a commercial kitchen due to having a constant heat source
▪ Are projective modules over a certain localised Laurent polynomial ring free?
▪ Why would this microphone only work while touching the volume control?
▪ Do Karaite Jews believe in Mashiach?
▪ Is it valid to modify a student's exam grade if you feel they did not earn it?
▪ Why would witches be incapable of using wands?
▪ How did Italy and Germany get rubber in WWII?
▪ Estimate effort of a Salesforce-to-Salesforce project
▪ Are inverted scales a thing?
▪ How to clear all definitions matching f[1, ...] but not f[2, ...]?
▪ How beneficial are self-healing filesystems for general usage?
▪ When did God create the waters in Genesis 1:2?

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

You might also like