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.

blogroll

social