| 161 | Deprecating a feature |
| 162 | --------------------- |
| 163 | |
| 164 | There are a couple reasons that code in Django might be deprecated: |
| 165 | |
| 166 | * If a feature has been improved or modified in a backwards-incompatible way, |
| 167 | the old feature or behavior will be deprecated. |
| 168 | |
| 169 | * Sometimes Django will include a backport of a Python library that's not |
| 170 | included in a version of Python that Django currently supports. When Django |
| 171 | no longer needs to support the older versions of Python that don't include |
| 172 | the library, the library will be deprecated in Django. |
| 173 | |
| 174 | |
| 175 | As the :ref:`deprecation policy<internal-release-deprecation-policy>` describes, |
| 176 | the first release of Django that deprecates a feature (``A.B``) should raise a |
| 177 | ``PendingDeprecationWarning``. Assuming we have a good test coverage, these |
| 178 | warnings will be shown by the test suite when running it with warnings enabled: |
| 179 | ``python -Wall runtests.py``. This is annoying and the output of the test suite |
| 180 | should remain clean. Thus, when adding a ``PendingDeprecationWarning`` you |
| 181 | need to eliminate or silence any warnings generated when running the tests. |
| 182 | |
| 183 | The first step is to remove any use of the deprecated behavior by Django itself. |
| 184 | Next you can silence warnings in tests that actually test the deprecated |
| 185 | behavior in one of two ways: |
| 186 | |
| 187 | #) In a particular test:: |
| 188 | |
| 189 | import warnings |
| 190 | |
| 191 | def test_foo(self): |
| 192 | with warnings.catch_warnings(record=True) as w: |
| 193 | warnings.simplefilter("always") |
| 194 | # invoke deprecated behavior |
| 195 | # go ahead with the test |
| 196 | |
| 197 | #) For an entire test case, ``django.test.utils`` contains three helpful |
| 198 | mixins to silence warnings: ``IgnorePendingDeprecationWarningsMixin``, |
| 199 | ``IgnoreDeprecationWarningsMixin``, and |
| 200 | ``IgnoreAllDeprecationWarningsMixin``. For example:: |
| 201 | |
| 202 | from django.test.utils import IgnorePendingDeprecationWarningsMixin |
| 203 | |
| 204 | class MyDeprecatedTests(IgnorePendingDeprecationWarningsMixin, unittest.TestCase): |
| 205 | ... |
| 206 | |
| 207 | Finally, there are a couple of updates to Django's documentation to make: |
| 208 | |
| 209 | #) If the existing feature is documented, mark it deprecated in documentation |
| 210 | using the ``.. deprecated:: A.B`` annotation. Include a short description |
| 211 | and a note about the upgrade path if applicable. |
| 212 | |
| 213 | #) Add a description of the deprecated behavior, and the upgrade path if |
| 214 | applicable, to current the release notes (``docs/releases/A.B.txt``) under |
| 215 | the "Features deprecated in A.B" heading. |
| 216 | |
| 217 | #) Add an entry in the deprecation timeline (``docs/internals/deprecation.txt``) |
| 218 | under the ``A.B+2`` version describing what code will be removed. |
| 219 | |
| 220 | Once you have completed these steps, you are finished with the deprecation. |
| 221 | In each minor release, all ``PendingDeprecationWarning``\s are promoted to |
| 222 | ``DeprecationWarning``\s and any features marked with``DeprecationWarning`` |
| 223 | are removed. |
| 224 | |