Skip to content

Commit 8add7c5

Browse files
authored
Merge pull request #1455 from jeanas/versioning
Create a discussion on versioning
2 parents 76d9e77 + 1935669 commit 8add7c5

File tree

5 files changed

+203
-115
lines changed

5 files changed

+203
-115
lines changed

source/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@
150150
"flexx": ("https://flexx.readthedocs.io/en/latest/", None),
151151
"flit": ("https://flit.pypa.io/en/stable/", None),
152152
"nox": ("https://nox.thea.codes/en/latest/", None),
153+
"numpy": ("https://numpy.org/doc/stable/", None),
153154
"openstack": ("https://docs.openstack.org/glance/latest/", None),
154155
"packaging": ("https://packaging.pypa.io/en/latest/", None),
155156
"pip": ("https://pip.pypa.io/en/latest/", None),

source/discussions/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ specific topic. If you're just trying to get stuff done, see
88
.. toctree::
99
:maxdepth: 1
1010

11+
versioning
1112
deploying-python-applications
1213
pip-vs-easy-install
1314
install-requires-vs-requirements

source/discussions/versioning.rst

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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

source/guides/distributing-packages-using-setuptools.rst

Lines changed: 2 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -287,124 +287,11 @@ achieve cross-platform compatibility is to use :ref:`console_scripts` entry
287287
points (see below).
288288

289289

290-
291-
292-
.. _`Choosing a versioning scheme`:
293-
294290
Choosing a versioning scheme
295291
----------------------------
296292

297-
Standards compliance for interoperability
298-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
299-
300-
Different Python projects may use different versioning schemes based on the needs of that
301-
particular project, but all of them are required to comply with the flexible :pep:`public version
302-
scheme <440#public-version-identifiers>` specified
303-
in :pep:`440` in order to be supported in tools and libraries like ``pip``
304-
and ``setuptools``.
305-
306-
Here are some examples of compliant version numbers::
307-
308-
1.2.0.dev1 # Development release
309-
1.2.0a1 # Alpha Release
310-
1.2.0b1 # Beta Release
311-
1.2.0rc1 # Release Candidate
312-
1.2.0 # Final Release
313-
1.2.0.post1 # Post Release
314-
15.10 # Date based release
315-
23 # Serial release
316-
317-
To further accommodate historical variations in approaches to version numbering,
318-
:pep:`440` also defines a comprehensive technique for :pep:`version
319-
normalisation <440#normalization>` that maps
320-
variant spellings of different version numbers to a standardised canonical form.
321-
322-
Scheme choices
323-
~~~~~~~~~~~~~~
324-
325-
Semantic versioning (preferred)
326-
*******************************
327-
328-
For new projects, the recommended versioning scheme is based on `Semantic Versioning
329-
<https://semver.org/>`_, but adopts a different approach to handling pre-releases and
330-
build metadata.
331-
332-
The essence of semantic versioning is a 3-part MAJOR.MINOR.MAINTENANCE numbering scheme,
333-
where the project author increments:
334-
335-
1. MAJOR version when they make incompatible API changes,
336-
2. MINOR version when they add functionality in a backwards-compatible manner, and
337-
3. MAINTENANCE version when they make backwards-compatible bug fixes.
338-
339-
Adopting this approach as a project author allows users to make use of :pep:`"compatible release"
340-
<440#compatible-release>` specifiers, where
341-
``name ~= X.Y`` requires at least release X.Y, but also allows any later release with
342-
a matching MAJOR version.
343-
344-
Python projects adopting semantic versioning should abide by clauses 1-8 of the
345-
`Semantic Versioning 2.0.0 specification <https://semver.org/>`_.
346-
347-
Date based versioning
348-
*********************
349-
350-
Semantic versioning is not a suitable choice for all projects, such as those with a regular
351-
time based release cadence and a deprecation process that provides warnings for a number of
352-
releases prior to removal of a feature.
353-
354-
A key advantage of date based versioning is that it is straightforward to tell how old the
355-
base feature set of a particular release is given just the version number.
356-
357-
Version numbers for date based projects typically take the form of YEAR.MONTH (for example,
358-
``12.04``, ``15.10``).
359-
360-
Serial versioning
361-
*****************
362-
363-
This is the simplest possible versioning scheme, and consists of a single number which is
364-
incremented every release.
365-
366-
While serial versioning is very easy to manage as a developer, it is the hardest to track
367-
as an end user, as serial version numbers convey little or no information regarding API
368-
backwards compatibility.
369-
370-
Hybrid schemes
371-
**************
372-
373-
Combinations of the above schemes are possible. For example, a project may combine date
374-
based versioning with serial versioning to create a YEAR.SERIAL numbering scheme that
375-
readily conveys the approximate age of a release, but doesn't otherwise commit to a particular
376-
release cadence within the year.
377-
378-
Pre-release versioning
379-
~~~~~~~~~~~~~~~~~~~~~~
380-
381-
Regardless of the base versioning scheme, pre-releases for a given final release may be
382-
published as:
383-
384-
* zero or more dev releases (denoted with a ".devN" suffix)
385-
* zero or more alpha releases (denoted with a ".aN" suffix)
386-
* zero or more beta releases (denoted with a ".bN" suffix)
387-
* zero or more release candidates (denoted with a ".rcN" suffix)
388-
389-
``pip`` and other modern Python package installers ignore pre-releases by default when
390-
deciding which versions of dependencies to install.
391-
392-
393-
Local version identifiers
394-
~~~~~~~~~~~~~~~~~~~~~~~~~
395-
396-
Public version identifiers are designed to support distribution via
397-
:term:`PyPI <Python Package Index (PyPI)>`. Python's software distribution tools also support
398-
the notion of a :pep:`local version identifier
399-
<440#local-version-identifiers>`, which can be used to
400-
identify local development builds not intended for publication, or modified variants of a release
401-
maintained by a redistributor.
402-
403-
A local version identifier takes the form ``<public version identifier>+<local version label>``.
404-
For example::
405-
406-
1.2.0.dev1+hg.5.b11e5e6f0b0b # 5th VCS commit since 1.2.0.dev1 release
407-
1.2.1+fedora.4 # Package with downstream Fedora patches applied
293+
See :ref:`versioning` for information on common version schemes and how to
294+
choose between them.
408295

409296

410297
Working in "development mode"

source/specifications/version-specifiers.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ aside from always being the lowest possible value in the version ordering.
108108
sections.
109109

110110

111+
.. _local-version-identifiers:
112+
111113
Local version identifiers
112114
-------------------------
113115

0 commit comments

Comments
 (0)