Deprecation warnings in python
Crossposted here: http://www.jaggedverge.com/2016/09/deprecation-warnings-in-python/ (please ask questions or leave comments over there)
When you are maintaining a package you want to be able to deprecate functionality and be able to give your users advance warning when you know that something is going away in the future. Because we wish to warn users without breaking the code we want to have the ability to give information without changing the flow of execution. Luckily Python has standard library support for warnings in the warnings module.
One thing you'll notice is that warnings are actually in the standard exception hierarchy. Within this there's some subclasses of Warning that provide more specific categories. Just like exceptions choosing the most specific correct category is a good practice.
When you want to warn your users that something is going away in the future there's a PendingDeprecationWarning. Then when you actually deprecate it you can use DeprecationWarning.
The full list of categories can be found here: https://docs.python.org/3/library/warnings.html#warning-categories
The benefit of this approach is that by using convention you make your intentions to the users of your code unambiguous.
Here's an example of how this works with methods:
#deprecation_example.py import warnings class Example: def __init__(self): self.items = [3,4,6,2,1] def slow_sort(self): warnings.warn( "slow_sort is deprecated, use fast_sort instead", DeprecationWarning ) import time time.sleep(5) return sorted(self.items) def gone_in_future_version_sort(self): warnings.warn( "gone_in_future_version_sort will be deprecated in version 2, use fast_sort instead", PendingDeprecationWarning ) return sorted(self.items) def fast_sort(self): return sorted(self.items)
Now when we run this:
janis:~/deprecation_tutorial$ python3 Python 3.4.3+ (default, Oct 14 2015, 16:03:50) [GCC 5.2.1 20151010] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from deprecation_example import Example >>> test = Example() >>> test.slow_sort() [1, 2, 3, 4, 6] >>> test.gone_in_future_version_sort() [1, 2, 3, 4, 6] >>> test.fast_sort() [1, 2, 3, 4, 6]
Now notice that nothing appeared to happen here. This is good! Warnings are for the sake of the developers, we do not want the execution for the users to change when we introduce a warning.
So in order to get the information displayed we have to start the interpreter with a flag, -Wd:
janis:~/deprecation_tutorial$ python3 -Wd Python 3.4.3+ (default, Oct 14 2015, 16:03:50) [GCC 5.2.1 20151010] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from deprecation_example import Example >>> test = Example() >>> test.slow_sort() /home/janis/deprecation_tutorial/deprecation_example.py:11: DeprecationWarning: slow_sort is deprecated, use fast_sort instead DeprecationWarning [1, 2, 3, 4, 6] >>> test.gone_in_future_version_sort() /home/janis/deprecation_tutorial/deprecation_example.py:20: PendingDeprecationWarning: gone_in_future_version_sort will be deprecated in version 2, use fast_sort instead PendingDeprecationWarning [1, 2, 3, 4, 6] >>> test.fast_sort() [1, 2, 3, 4, 6]
Now we see the warnings!
Say we want to write some code in a script:
from deprecation_example import Example test_instance = Example() test_instance.slow_sort() test_instance.gone_in_future_version_sort() test_instance.fast_sort()
Just like the REPL example running this with no flags to python will not display any warnings output.
janis:~/deprecation_tutorial$ python3 test_script.py janis:~/deprecation_tutorial$
Invoking the interpreter with the -Wd flag will however give us info:
janis:~/deprecation_tutorial$ python3 -Wd test_script.py /home/janis/deprecation_tutorial/deprecation_example.py:11: DeprecationWarning: slow_sort is deprecated, use fast_sort instead DeprecationWarning /home/janis/deprecation_tutorial/deprecation_example.py:20: PendingDeprecationWarning: gone_in_future_version_sort will be deprecated in version 2, use fast_sort instead PendingDeprecationWarning
Now say we wanted to do that via code:
import warnings warnings.simplefilter('default') from deprecation_example import Example test_instance = Example() test_instance.slow_sort() test_instance.gone_in_future_version_sort() test_instance.fast_sort()
Now we have set it up we get the warning reporting even without the interpreter flag:
janis:~/deprecation_tutorial$ python3 test_script.py /home/janis/deprecation_tutorial/deprecation_example.py:11: DeprecationWarning: slow_sort is deprecated, use fast_sort instead DeprecationWarning /home/janis/deprecation_tutorial/deprecation_example.py:20: PendingDeprecationWarning: gone_in_future_version_sort will be deprecated in version 2, use fast_sort instead PendingDeprecationWarning
Note that if you are using the standard library logging you can set it up to log all warnings with logging.captureWarnings . In production systems this is a very good idea, as you want to gather as much information as you can about things that will impact your code.
Deprecating at module level scope
You may have noticed that we were able to make a call to warnings inside the flow of control for the portion we were deprecating. If something is at the top level scope we can't do that, check out the post about deprecating module scope variables to see how you can deal with that.