Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a discussion on versioning #1455

Merged
merged 9 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/discussions/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ specific topic. If you're just trying to get stuff done, see
.. toctree::
:maxdepth: 1

versioning
webknjaz marked this conversation as resolved.
Show resolved Hide resolved
deploying-python-applications
pip-vs-easy-install
install-requires-vs-requirements
Expand Down
139 changes: 139 additions & 0 deletions source/discussions/versioning.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
.. _versioning:
.. _`Choosing a versioning scheme`:

==========
Versioning
==========

This discussion covers all aspects of versioning Python packages.


Valid version numbers
=====================

Different Python projects may use different versioning schemes based on the
needs of that particular project, but in order to be compatible with tools like
:ref:`pip`, all of them are required to comply with a flexible format for
version identifiers, for which the authoritative reference is the
:ref:`specification of version specifiers <version-specifiers>`. Here are some
examples of version numbers:

.. code-block:: text

1.2.0.dev1 # Development release
jeanas marked this conversation as resolved.
Show resolved Hide resolved
1.2.0a1 # Alpha Release
1.2.0b1 # Beta Release
1.2.0rc1 # Release Candidate
1.2.0 # Final Release
1.2.0.post1 # Post Release
jeanas marked this conversation as resolved.
Show resolved Hide resolved
15.10 # Date based release
23 # Serial release


Semantic versioning vs. calendar versioning
===========================================

A versioning scheme is a way to interpret version numbers of a package, and to
jeanas marked this conversation as resolved.
Show resolved Hide resolved
decide which should be the next version number for a new release of a package.
Two versioning schemes are commonly used for Python packages, semantic
versioning and calendar versioning.

jeanas marked this conversation as resolved.
Show resolved Hide resolved
Semantic versioning is recommended for most new projects.
jeanas marked this conversation as resolved.
Show resolved Hide resolved

Semantic versioning
-------------------

The idea of *semantic versioning* is to use 3-part version numbers,
*major.minor.maintenance*, where the project author increments:
webknjaz marked this conversation as resolved.
Show resolved Hide resolved

- *major* when they make incompatible API changes,
- *minor* when they add functionality in a backwards-compatible manner, and
- *maintenance*, when they make backwards-compatible bug fixes.

Note that many projects, especially larger ones, do not use strict semantic
versioning since many changes are technically breaking changes but affect only a
small fraction of users. Such projects tend to increment the major number when
the incompatibility is high, rather than for any tiny incompatibility, or to
signal a shift in the project.

jeanas marked this conversation as resolved.
Show resolved Hide resolved
For those projects that do adhere to semantic versioning strictly, this approach
allows users to make use of :ref:`compatible release version specifiers
<version-specifiers-compatible-release>`, with the ``~=`` operator. For
example, ``name ~= X.Y`` is roughly equivalent to ``name >= X.Y, == X.*``, i.e.,
it requires at least release X.Y, and allows any later release with greater Y as
long as X is the same. Likewise, ``name ~= X.Y.Z`` is roughly equivalent to
``name >= X.Y.Z, == X.Y.*``, i.e., it requires at least X.Y.Z and allows a later
release with same X and Y but higher Z.

Python projects adopting semantic versioning should abide by clauses 1-8 of the
`Semantic Versioning 2.0.0 specification <semver_>`_.


Calendar versioning
-------------------

Semantic versioning is not a suitable choice for all projects, such as those
with a regular time based release cadence and a deprecation process that
provides warnings for a number of releases prior to removal of a feature.

A key advantage of date-based versioning, or `calendar versioning <calver_>`_,
is that it is straightforward to tell how old the base feature set of a
particular release is given just the version number.

Calendar version numbers typically take the form *year.month* (for example,
23.10 for December 2023).
jeanas marked this conversation as resolved.
Show resolved Hide resolved


Other schemes
-------------

Serial versioning refers to the simplest possible versioning scheme, which
jeanas marked this conversation as resolved.
Show resolved Hide resolved
consists of a single number incremented every release. While serial versioning
is very easy to manage as a developer, it is the hardest to track as an end
user, as serial version numbers convey little or no information regarding API
backwards compatibility.

Combinations of the above schemes are possible. For example, a project may
combine date based versioning with serial versioning to create a *year.serial*
numbering scheme that readily conveys the approximate age of a release, but
doesn't otherwise commit to a particular release cadence within the year.



Pre-release versioning
======================

Regardless of the base versioning scheme, pre-releases for a given final release
may be published as:

* Zero or more dev releases, denoted with a ".devN" suffix,
* Zero or more alpha releases, denoted with a ".aN" suffix,
* Zero or more beta releases, denoted with a ".bN" suffix,
* Zero or more release candidates, denoted with a ".rcN" suffix.

Pip and other modern Python package installers ignore pre-releases by default
jeanas marked this conversation as resolved.
Show resolved Hide resolved
when deciding which versions of dependencies to install.


Local version identifiers
=========================

Public version identifiers are designed to support distribution via :term:`PyPI
<Python Package Index (PyPI)>`. Python packaging tools also support the notion
of a :ref:`local version identifier <local-version-identifiers>`, which can be
used to identify local development builds not intended for publication, or
modified variants of a release maintained by a redistributor.

A local version identifier takes the form of a public version identifier,
followed by "+" and a local version label. For example:

.. code-block:: text

1.2.0.dev1+hg.5.b11e5e6f0b0b # 5th VCS commit since 1.2.0.dev1 release
jeanas marked this conversation as resolved.
Show resolved Hide resolved
1.2.1+fedora.4 # Package with downstream Fedora patches applied




.. _calver: https://calver.org
.. _semver: https://semver.org
119 changes: 0 additions & 119 deletions source/guides/distributing-packages-using-setuptools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -288,125 +288,6 @@ points (see below).




webknjaz marked this conversation as resolved.
Show resolved Hide resolved
.. _`Choosing a versioning scheme`:

Choosing a versioning scheme
----------------------------

Standards compliance for interoperability
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Different Python projects may use different versioning schemes based on the needs of that
particular project, but all of them are required to comply with the flexible :pep:`public version
scheme <440#public-version-identifiers>` specified
in :pep:`440` in order to be supported in tools and libraries like ``pip``
and ``setuptools``.

Here are some examples of compliant version numbers::

1.2.0.dev1 # Development release
1.2.0a1 # Alpha Release
1.2.0b1 # Beta Release
1.2.0rc1 # Release Candidate
1.2.0 # Final Release
1.2.0.post1 # Post Release
15.10 # Date based release
23 # Serial release

To further accommodate historical variations in approaches to version numbering,
:pep:`440` also defines a comprehensive technique for :pep:`version
normalisation <440#normalization>` that maps
variant spellings of different version numbers to a standardised canonical form.

Scheme choices
~~~~~~~~~~~~~~

Semantic versioning (preferred)
*******************************

For new projects, the recommended versioning scheme is based on `Semantic Versioning
<https://semver.org/>`_, but adopts a different approach to handling pre-releases and
build metadata.

The essence of semantic versioning is a 3-part MAJOR.MINOR.MAINTENANCE numbering scheme,
where the project author increments:

1. MAJOR version when they make incompatible API changes,
2. MINOR version when they add functionality in a backwards-compatible manner, and
3. MAINTENANCE version when they make backwards-compatible bug fixes.

Adopting this approach as a project author allows users to make use of :pep:`"compatible release"
<440#compatible-release>` specifiers, where
``name ~= X.Y`` requires at least release X.Y, but also allows any later release with
a matching MAJOR version.

Python projects adopting semantic versioning should abide by clauses 1-8 of the
`Semantic Versioning 2.0.0 specification <https://semver.org/>`_.

Date based versioning
*********************

Semantic versioning is not a suitable choice for all projects, such as those with a regular
time based release cadence and a deprecation process that provides warnings for a number of
releases prior to removal of a feature.

A key advantage of date based versioning is that it is straightforward to tell how old the
base feature set of a particular release is given just the version number.

Version numbers for date based projects typically take the form of YEAR.MONTH (for example,
``12.04``, ``15.10``).

Serial versioning
*****************

This is the simplest possible versioning scheme, and consists of a single number which is
incremented every release.

While serial versioning is very easy to manage as a developer, it is the hardest to track
as an end user, as serial version numbers convey little or no information regarding API
backwards compatibility.

Hybrid schemes
**************

Combinations of the above schemes are possible. For example, a project may combine date
based versioning with serial versioning to create a YEAR.SERIAL numbering scheme that
readily conveys the approximate age of a release, but doesn't otherwise commit to a particular
release cadence within the year.

Pre-release versioning
~~~~~~~~~~~~~~~~~~~~~~

Regardless of the base versioning scheme, pre-releases for a given final release may be
published as:

* zero or more dev releases (denoted with a ".devN" suffix)
* zero or more alpha releases (denoted with a ".aN" suffix)
* zero or more beta releases (denoted with a ".bN" suffix)
* zero or more release candidates (denoted with a ".rcN" suffix)

``pip`` and other modern Python package installers ignore pre-releases by default when
deciding which versions of dependencies to install.


Local version identifiers
~~~~~~~~~~~~~~~~~~~~~~~~~

Public version identifiers are designed to support distribution via
:term:`PyPI <Python Package Index (PyPI)>`. Python's software distribution tools also support
the notion of a :pep:`local version identifier
<440#local-version-identifiers>`, which can be used to
identify local development builds not intended for publication, or modified variants of a release
maintained by a redistributor.

A local version identifier takes the form ``<public version identifier>+<local version label>``.
For example::

1.2.0.dev1+hg.5.b11e5e6f0b0b # 5th VCS commit since 1.2.0.dev1 release
1.2.1+fedora.4 # Package with downstream Fedora patches applied


Working in "development mode"
=============================

Expand Down
2 changes: 2 additions & 0 deletions source/specifications/version-specifiers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ aside from always being the lowest possible value in the version ordering.
sections.


.. _local-version-identifiers:

Local version identifiers
-------------------------

Expand Down