aboutsummaryrefslogtreecommitdiff
path: root/docs/deprecation-policy.rst
blob: 0879406815044b9553fcf99362d4d958663024f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
.. _deprecation-policy:

Deprecation Policy
==================

This policy governs how every removed, renamed, or behavior-changed public API
in Edify **1.0 and later** communicates the change to existing users. It does
not apply to the 0.3 → 1.0 transition, which is a clean redesign with no
deprecation stubs — see :ref:`upgrading-0-3-to-1-0` for that move.

The stub pattern
----------------

When a public symbol is renamed or removed, the old name stays importable for one
minor-release cycle as a **deprecation stub**. The stub forwards to the new
implementation (for a rename) or raises on use (for a removal), and always emits
a :class:`DeprecationWarning` on first use.

.. code-block:: python

    import warnings

    def old_name(*args, **kwargs):
        warnings.warn(
            "old_name is deprecated since 1.1; use new_name. "
            "See https://edify.readthedocs.io/en/latest/upgrading/1.0-to-1.1.html#new-name",
            DeprecationWarning,
            stacklevel=2,
        )
        return new_name(*args, **kwargs)

Message format
--------------

Every deprecation warning message follows this exact shape::

    <name> is deprecated since <version>; use <replacement>. See <docs-url>

* ``<name>`` — the deprecated symbol, spelled exactly as the user typed it.
* ``<version>`` — the release that introduced the deprecation.
* ``<replacement>`` — the symbol to use instead, or a one-clause instruction
  when there is no drop-in replacement.
* ``<docs-url>`` — an absolute URL into the upgrade guide, ending in the frozen
  ``#anchor`` for the relevant section. The anchor is a
  ``.. _label:`` target under ``docs/upgrading/``, decoupled from the heading
  text so rewording a heading never breaks the link.

Warning category and stacklevel
-------------------------------

* The category is always :class:`DeprecationWarning`.
* ``stacklevel=2`` so the warning points at the caller's line, not at the stub.
* Each stub fires its warning **exactly once per call site** — it never suppresses
  or batches, and it never fires at import time.

Removal cadence
---------------

* A symbol deprecated in release ``X.Y`` remains importable through the end of the
  ``X.(Y+1)`` line and is removed no earlier than ``X.(Y+2)``.
* Removals only land in a minor or major release, never a patch release.
* The removal is recorded as a breaking change in the CHANGELOG and gets its own
  section (with a frozen anchor) in the matching upgrade guide.

Behavior-change rule
--------------------

A change to what an existing, unchanged call *returns* or *raises* — with no
change to its name or signature — is a breaking change even though nothing looks
different at the call site. It is documented in the upgrade guide with a
before/after, cross-linked from the CHANGELOG, and (where technically possible)
announced with a :class:`DeprecationWarning` for one cycle before the new
behavior becomes the default.