|
| 1 | +.. _versioning: |
| 2 | +.. _`Choosing a versioning scheme`: |
| 3 | + |
| 4 | +========== |
| 5 | +Versioning |
| 6 | +========== |
| 7 | + |
| 8 | +This discussion covers all aspects of versioning Python packages. |
| 9 | + |
| 10 | + |
| 11 | +Valid version numbers |
| 12 | +===================== |
| 13 | + |
| 14 | +Different Python projects may use different versioning schemes based on the |
| 15 | +needs of that particular project, but in order to be compatible with tools like |
| 16 | +:ref:`pip`, all of them are required to comply with a flexible format for |
| 17 | +version identifiers, for which the authoritative reference is the |
| 18 | +:ref:`specification of version specifiers <version-specifiers>`. Here are some |
| 19 | +examples of version numbers [#version-examples]_: |
| 20 | + |
| 21 | +- A simple version (final release): ``1.2.0`` |
| 22 | +- A development release: ``1.2.0.dev1`` |
| 23 | +- An alpha release: ``1.2.0a1`` |
| 24 | +- A beta release: ``1.2.0b1`` |
| 25 | +- A release candidate: ``1.2.0rc1`` |
| 26 | +- A post-release: ``1.2.0.post1`` |
| 27 | +- A post-release of an alpha release (possible, but discouraged): ``1.2.0a1.post1`` |
| 28 | +- A simple version with only two components: ``23.12`` |
| 29 | +- A simple version with just one component: ``42`` |
| 30 | +- A version with an epoch: ``1!1.0`` |
| 31 | + |
| 32 | +Projects can use a cycle of pre-releases to support testing by their users |
| 33 | +before a final release. In order, the steps are: alpha releases, beta releases, |
| 34 | +release candidates, final release. Pip and other modern Python package |
| 35 | +installers ignore pre-releases by default when deciding which versions of |
| 36 | +dependencies to install, unless explicitly requested (e.g., with |
| 37 | +``pip install pkg==1.1a3`` or ``pip install --pre pkg``). |
| 38 | + |
| 39 | +The purpose of development releases is to support releases made early during a |
| 40 | +development cycle, for example, a nightly build, or a build from the latest |
| 41 | +source in a Linux distribution. |
| 42 | + |
| 43 | +Post-releases are used to address minor errors in a final release that do not |
| 44 | +affect the distributed software, such as correcting an error in the release |
| 45 | +notes. They should not be used for bug fixes; these should be done with a new |
| 46 | +final release (e.g., incrementing the third component when using semantic |
| 47 | +versioning). |
| 48 | + |
| 49 | +Finally, epochs, a rarely used feature, serve to fix the sorting order when |
| 50 | +changing the versioning scheme. For example, if a project is using calendar |
| 51 | +versioning, with versions like 23.12, and switches to semantic versioning, with |
| 52 | +versions like 1.0, the comparison between 1.0 and 23.12 will go the wrong way. |
| 53 | +To correct this, the new version numbers should have an explicit epoch, as in |
| 54 | +"1!1.0", in order to be treated as more recent than the old version numbers. |
| 55 | + |
| 56 | + |
| 57 | + |
| 58 | +Semantic versioning vs. calendar versioning |
| 59 | +=========================================== |
| 60 | + |
| 61 | +A versioning scheme is a formalized way to interpret the segments of a version |
| 62 | +number, and to decide which should be the next version number for a new release |
| 63 | +of a package. Two versioning schemes are commonly used for Python packages, |
| 64 | +semantic versioning and calendar versioning. |
| 65 | + |
| 66 | +.. caution:: |
| 67 | + |
| 68 | + The decision which version number to choose is up to a |
| 69 | + project's maintainer. This effectively means that version |
| 70 | + bumps reflect the maintainer's view. That view may differ |
| 71 | + from the end-users' perception of what said formalized |
| 72 | + versioning scheme promises them. |
| 73 | + |
| 74 | + There are known exceptions for selecting the next version |
| 75 | + number. The maintainers may consciously choose to break the |
| 76 | + assumption that the last version segment only contains |
| 77 | + backwards-compatible changes. |
| 78 | + One such case is when security vulnerability needs to be |
| 79 | + addressed. Security releases often come in patch versions |
| 80 | + but contain breaking changes inevitably. |
| 81 | + |
| 82 | + |
| 83 | +Semantic versioning |
| 84 | +------------------- |
| 85 | + |
| 86 | +The idea of *semantic versioning* (or SemVer) is to use 3-part version numbers, |
| 87 | +*major.minor.patch*, where the project author increments: |
| 88 | + |
| 89 | +- *major* when they make incompatible API changes, |
| 90 | +- *minor* when they add functionality in a backwards-compatible manner, and |
| 91 | +- *patch*, when they make backwards-compatible bug fixes. |
| 92 | + |
| 93 | +A majority of Python projects use a scheme that resembles semantic |
| 94 | +versioning. However, most projects, especially larger ones, do not strictly |
| 95 | +adhere to semantic versioning, since many changes are technically breaking |
| 96 | +changes but affect only a small fraction of users. Such projects tend to |
| 97 | +increment the major number when the incompatibility is high, or to signal a |
| 98 | +shift in the project, rather than for any tiny incompatibility |
| 99 | +[#semver-strictness]_. Conversely, a bump of the major version number |
| 100 | +is sometimes used to signal significant but backwards-compatible new |
| 101 | +features. |
| 102 | + |
| 103 | +For those projects that do use strict semantic versioning, this approach allows |
| 104 | +users to make use of :ref:`compatible release version specifiers |
| 105 | +<version-specifiers-compatible-release>`, with the ``~=`` operator. For |
| 106 | +example, ``name ~= X.Y`` is roughly equivalent to ``name >= X.Y, == X.*``, i.e., |
| 107 | +it requires at least release X.Y, and allows any later release with greater Y as |
| 108 | +long as X is the same. Likewise, ``name ~= X.Y.Z`` is roughly equivalent to |
| 109 | +``name >= X.Y.Z, == X.Y.*``, i.e., it requires at least X.Y.Z and allows a later |
| 110 | +release with same X and Y but higher Z. |
| 111 | + |
| 112 | +Python projects adopting semantic versioning should abide by clauses 1-8 of the |
| 113 | +`Semantic Versioning 2.0.0 specification <semver_>`_. |
| 114 | + |
| 115 | +The popular :doc:`Sphinx <sphinx:index>` documentation generator is an example |
| 116 | +project that uses strict semantic versioning (:doc:`Sphinx versioning policy |
| 117 | +<sphinx:internals/release-process>`). The famous :doc:`NumPy <numpy:index>` |
| 118 | +scientific computing package explicitly uses "loose" semantic versioning, where |
| 119 | +releases incrementing the minor version can contain backwards-incompatible API |
| 120 | +changes (:doc:`NumPy versioning policy <numpy:dev/depending_on_numpy>`). |
| 121 | + |
| 122 | + |
| 123 | +Calendar versioning |
| 124 | +------------------- |
| 125 | + |
| 126 | +Semantic versioning is not a suitable choice for all projects, such as those |
| 127 | +with a regular time based release cadence and a deprecation process that |
| 128 | +provides warnings for a number of releases prior to removal of a feature. |
| 129 | + |
| 130 | +A key advantage of date-based versioning, or `calendar versioning <calver_>`_ |
| 131 | +(CalVer), is that it is straightforward to tell how old the base feature set of |
| 132 | +a particular release is given just the version number. |
| 133 | + |
| 134 | +Calendar version numbers typically take the form *year.month* (for example, |
| 135 | +23.12 for December 2023). |
| 136 | + |
| 137 | +:doc:`Pip <pip:index>`, the standard Python package installer, uses calendar |
| 138 | +versioning. |
| 139 | + |
| 140 | + |
| 141 | +Other schemes |
| 142 | +------------- |
| 143 | + |
| 144 | +Serial versioning refers to the simplest possible versioning scheme, which |
| 145 | +consists of a single number incremented every release. While serial versioning |
| 146 | +is very easy to manage as a developer, it is the hardest to track as an end |
| 147 | +user, as serial version numbers convey little or no information regarding API |
| 148 | +backwards compatibility. |
| 149 | + |
| 150 | +Combinations of the above schemes are possible. For example, a project may |
| 151 | +combine date based versioning with serial versioning to create a *year.serial* |
| 152 | +numbering scheme that readily conveys the approximate age of a release, but |
| 153 | +doesn't otherwise commit to a particular release cadence within the year. |
| 154 | + |
| 155 | + |
| 156 | + |
| 157 | +Local version identifiers |
| 158 | +========================= |
| 159 | + |
| 160 | +Public version identifiers are designed to support distribution via :term:`PyPI |
| 161 | +<Python Package Index (PyPI)>`. Python packaging tools also support the notion |
| 162 | +of a :ref:`local version identifier <local-version-identifiers>`, which can be |
| 163 | +used to identify local development builds not intended for publication, or |
| 164 | +modified variants of a release maintained by a redistributor. |
| 165 | + |
| 166 | +A local version identifier takes the form of a public version identifier, |
| 167 | +followed by "+" and a local version label. For example, a package with |
| 168 | +Fedora-specific patches applied could have the version "1.2.1+fedora.4". |
| 169 | +Another example is versions computed by setuptools-scm_, a setuptools plugin |
| 170 | +that reads the version from Git data. In a Git repository with some commits |
| 171 | +since the latest release, setuptools-scm generates a version like |
| 172 | +"0.5.dev1+gd00980f", or if the repository has untracked changes, like |
| 173 | +"0.5.dev1+gd00980f.d20231217". |
| 174 | + |
| 175 | + |
| 176 | +-------------------------------------------------------------------------------- |
| 177 | + |
| 178 | +.. [#version-examples] Some more examples of unusual version numbers are |
| 179 | + given in a `blog post <versions-seth-larson_>`_ by Seth Larson. |
| 180 | +
|
| 181 | +.. [#semver-strictness] For some personal viewpoints on this issue, see these |
| 182 | + blog posts: `by Hynek Schlawak <semver-hynek-schlawack_>`_, `by Donald Stufft |
| 183 | + <semver-donald-stufft_>`_, `by Bernát Gábor <semver-bernat-gabor_>`_, `by |
| 184 | + Brett Cannon <semver-brett-cannon_>`_. For a humoristic take, read about |
| 185 | + ZeroVer_. |
| 186 | +
|
| 187 | +
|
| 188 | +
|
| 189 | +.. _zerover: https://0ver.org |
| 190 | +.. _calver: https://calver.org |
| 191 | +.. _semver: https://semver.org |
| 192 | +.. _semver-bernat-gabor: https://bernat.tech/posts/version-numbers/ |
| 193 | +.. _semver-brett-cannon: https://snarky.ca/why-i-dont-like-semver/ |
| 194 | +.. _semver-donald-stufft: https://caremad.io/posts/2016/02/versioning-software/ |
| 195 | +.. _semver-hynek-schlawack: https://hynek.me/articles/semver-will-not-save-you/ |
| 196 | +.. _setuptools-scm: https://setuptools-scm.readthedocs.io |
| 197 | +.. _versions-seth-larson: https://sethmlarson.dev/pep-440 |
0 commit comments