2011-04-05 14:47:18 -04:00
|
|
|
|
PEP: 396
|
|
|
|
|
Title: Module Version Numbers
|
|
|
|
|
Version: $Revision: 65628 $
|
|
|
|
|
Last-Modified: $Date: 2008-08-10 09:59:20 -0400 (Sun, 10 Aug 2008) $
|
|
|
|
|
Author: Barry Warsaw <barry@python.org>
|
2021-04-14 18:08:26 -04:00
|
|
|
|
Status: Rejected
|
2011-04-05 14:47:18 -04:00
|
|
|
|
Type: Informational
|
|
|
|
|
Content-Type: text/x-rst
|
2021-02-09 11:54:26 -05:00
|
|
|
|
Created: 16-Mar-2011
|
2011-04-05 14:48:30 -04:00
|
|
|
|
Post-History: 2011-04-05
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
Given that it is useful and common to specify version numbers for
|
|
|
|
|
Python modules, and given that different ways of doing this have grown
|
|
|
|
|
organically within the Python community, it is useful to establish
|
|
|
|
|
standard conventions for module authors to adhere to and reference.
|
|
|
|
|
This informational PEP describes best practices for Python module
|
|
|
|
|
authors who want to define the version number of their Python module.
|
|
|
|
|
|
|
|
|
|
Conformance with this PEP is optional, however other Python tools
|
|
|
|
|
(such as ``distutils2`` [1]_) may be adapted to use the conventions
|
|
|
|
|
defined here.
|
|
|
|
|
|
2021-04-14 18:08:26 -04:00
|
|
|
|
PEP Rejection
|
|
|
|
|
=============
|
2013-05-18 03:50:40 -04:00
|
|
|
|
|
2021-04-14 18:08:26 -04:00
|
|
|
|
This PEP was formally rejected on 2021-04-14. The packaging ecosystem
|
|
|
|
|
has changed significantly in the intervening years since this PEP was
|
|
|
|
|
first written, and APIs such as ``importlib.metadata.versions()`` [11]_
|
|
|
|
|
provide for a much better experience.
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
|
|
|
|
User Stories
|
|
|
|
|
============
|
|
|
|
|
|
|
|
|
|
Alice is writing a new module, called ``alice``, which she wants to
|
|
|
|
|
share with other Python developers. ``alice`` is a simple module and
|
|
|
|
|
lives in one file, ``alice.py``. Alice wants to specify a version
|
|
|
|
|
number so that her users can tell which version they are using.
|
|
|
|
|
Because her module lives entirely in one file, she wants to add the
|
|
|
|
|
version number to that file.
|
|
|
|
|
|
|
|
|
|
Bob has written a module called ``bob`` which he has shared with many
|
|
|
|
|
users. ``bob.py`` contains a version number for the convenience of
|
|
|
|
|
his users. Bob learns about the Cheeseshop [2]_, and adds some simple
|
|
|
|
|
packaging using classic distutils so that he can upload *The Bob
|
|
|
|
|
Bundle* to the Cheeseshop. Because ``bob.py`` already specifies a
|
|
|
|
|
version number which his users can access programmatically, he wants
|
|
|
|
|
the same API to continue to work even though his users now get it from
|
|
|
|
|
the Cheeseshop.
|
|
|
|
|
|
2013-03-18 12:23:56 -04:00
|
|
|
|
Carol maintains several namespace packages, each of which are
|
2011-04-05 14:47:18 -04:00
|
|
|
|
independently developed and distributed. In order for her users to
|
|
|
|
|
properly specify dependencies on the right versions of her packages,
|
|
|
|
|
she specifies the version numbers in the namespace package's
|
|
|
|
|
``setup.py`` file. Because Carol wants to have to update one version
|
|
|
|
|
number per package, she specifies the version number in her module and
|
|
|
|
|
has the ``setup.py`` extract the module version number when she builds
|
|
|
|
|
the *sdist* archive.
|
|
|
|
|
|
|
|
|
|
David maintains a package in the standard library, and also produces
|
|
|
|
|
standalone versions for other versions of Python. The standard
|
|
|
|
|
library copy defines the version number in the module, and this same
|
|
|
|
|
version number is used for the standalone distributions as well.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
Python modules, both in the standard library and available from third
|
|
|
|
|
parties, have long included version numbers. There are established
|
2016-07-11 11:14:08 -04:00
|
|
|
|
de facto standards for describing version numbers, and many ad-hoc
|
2011-04-05 14:47:18 -04:00
|
|
|
|
ways have grown organically over the years. Often, version numbers
|
|
|
|
|
can be retrieved from a module programmatically, by importing the
|
|
|
|
|
module and inspecting an attribute. Classic Python distutils
|
|
|
|
|
``setup()`` functions [3]_ describe a ``version`` argument where the
|
2022-01-21 06:03:51 -05:00
|
|
|
|
release's version number can be specified. :pep:`8` describes the
|
2011-04-05 14:47:18 -04:00
|
|
|
|
use of a module attribute called ``__version__`` for recording
|
|
|
|
|
"Subversion, CVS, or RCS" version strings using keyword expansion. In
|
|
|
|
|
the PEP author's own email archives, the earliest example of the use
|
|
|
|
|
of an ``__version__`` module attribute by independent module
|
|
|
|
|
developers dates back to 1995.
|
|
|
|
|
|
2011-04-13 15:21:13 -04:00
|
|
|
|
Another example of version information is the sqlite3 [5]_ module
|
2011-04-05 14:47:18 -04:00
|
|
|
|
with its ``sqlite_version_info``, ``version``, and ``version_info``
|
|
|
|
|
attributes. It may not be immediately obvious which attribute
|
|
|
|
|
contains a version number for the module, and which contains a version
|
|
|
|
|
number for the underlying SQLite3 library.
|
|
|
|
|
|
|
|
|
|
This informational PEP codifies established practice, and recommends
|
|
|
|
|
standard ways of describing module version numbers, along with some
|
|
|
|
|
use cases for when -- and when *not* -- to include them. Its adoption
|
|
|
|
|
by module authors is purely voluntary; packaging tools in the standard
|
|
|
|
|
library will provide optional support for the standards defined
|
|
|
|
|
herein, and other tools in the Python universe may comply as well.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
#. In general, modules in the standard library SHOULD NOT have version
|
|
|
|
|
numbers. They implicitly carry the version number of the Python
|
|
|
|
|
release they are included in.
|
|
|
|
|
|
|
|
|
|
#. On a case-by-case basis, standard library modules which are also
|
|
|
|
|
released in standalone form for other Python versions MAY include a
|
|
|
|
|
module version number when included in the standard library, and
|
|
|
|
|
SHOULD include a version number when packaged separately.
|
|
|
|
|
|
2012-05-03 14:30:48 -04:00
|
|
|
|
#. When a module (or package) includes a version number, the version
|
|
|
|
|
SHOULD be available in the ``__version__`` attribute.
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
2012-05-03 14:30:48 -04:00
|
|
|
|
#. For modules which live inside a namespace package, the module
|
|
|
|
|
SHOULD include the ``__version__`` attribute. The namespace
|
|
|
|
|
package itself SHOULD NOT include its own ``__version__``
|
|
|
|
|
attribute.
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
|
|
|
|
#. The ``__version__`` attribute's value SHOULD be a string.
|
|
|
|
|
|
|
|
|
|
#. Module version numbers SHOULD conform to the normalized version
|
2022-01-21 06:03:51 -05:00
|
|
|
|
format specified in :pep:`386`.
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
|
|
|
|
#. Module version numbers SHOULD NOT contain version control system
|
|
|
|
|
supplied revision numbers, or any other semantically different
|
|
|
|
|
version numbers (e.g. underlying library version number).
|
|
|
|
|
|
|
|
|
|
#. The ``version`` attribute in a classic distutils ``setup.py``
|
2022-01-21 06:03:51 -05:00
|
|
|
|
file, or the :pep:`345` ``Version`` metadata field SHOULD be
|
2011-04-05 14:47:18 -04:00
|
|
|
|
derived from the ``__version__`` field, or vice versa.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
Retrieving the version number from a third party package::
|
|
|
|
|
|
|
|
|
|
>>> import bzrlib
|
|
|
|
|
>>> bzrlib.__version__
|
|
|
|
|
'2.3.0'
|
|
|
|
|
|
|
|
|
|
Retrieving the version number from a standard library package that is
|
|
|
|
|
also distributed as a standalone module::
|
|
|
|
|
|
|
|
|
|
>>> import email
|
|
|
|
|
>>> email.__version__
|
|
|
|
|
'5.1.0'
|
|
|
|
|
|
|
|
|
|
Version numbers for namespace packages::
|
|
|
|
|
|
|
|
|
|
>>> import flufl.i18n
|
|
|
|
|
>>> import flufl.enum
|
|
|
|
|
>>> import flufl.lock
|
|
|
|
|
|
|
|
|
|
>>> print flufl.i18n.__version__
|
|
|
|
|
1.0.4
|
|
|
|
|
>>> print flufl.enum.__version__
|
|
|
|
|
3.1
|
|
|
|
|
>>> print flufl.lock.__version__
|
|
|
|
|
2.1
|
|
|
|
|
|
|
|
|
|
>>> import flufl
|
|
|
|
|
>>> flufl.__version__
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
|
AttributeError: 'module' object has no attribute '__version__'
|
|
|
|
|
>>>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Deriving
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
Module version numbers can appear in at least two places, and
|
|
|
|
|
sometimes more. For example, in accordance with this PEP, they are
|
|
|
|
|
available programmatically on the module's ``__version__`` attribute.
|
|
|
|
|
In a classic distutils ``setup.py`` file, the ``setup()`` function
|
|
|
|
|
takes a ``version`` argument, while the distutils2 ``setup.cfg`` file
|
|
|
|
|
has a ``version`` key. The version number must also get into the PEP
|
|
|
|
|
345 metadata, preferably when the *sdist* archive is built. It's
|
|
|
|
|
desirable for module authors to only have to specify the version
|
|
|
|
|
number once, and have all the other uses derive from this single
|
|
|
|
|
definition.
|
|
|
|
|
|
2011-04-13 15:21:13 -04:00
|
|
|
|
This could be done in any number of ways, a few of which are outlined
|
|
|
|
|
below. These are included for illustrative purposes only and are not
|
|
|
|
|
intended to be definitive, complete, or all-encompassing. Other
|
|
|
|
|
approaches are possible, and some included below may have limitations
|
|
|
|
|
that prevent their use in some situations.
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
|
|
|
|
Let's say Elle adds this attribute to her module file ``elle.py``::
|
|
|
|
|
|
|
|
|
|
__version__ = '3.1.1'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Classic distutils
|
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
|
|
In classic distutils, the simplest way to add the version string to
|
|
|
|
|
the ``setup()`` function in ``setup.py`` is to do something like
|
|
|
|
|
this::
|
|
|
|
|
|
|
|
|
|
from elle import __version__
|
|
|
|
|
setup(name='elle', version=__version__)
|
|
|
|
|
|
|
|
|
|
In the PEP author's experience however, this can fail in some cases,
|
|
|
|
|
such as when the module uses automatic Python 3 conversion via the
|
|
|
|
|
``2to3`` program (because ``setup.py`` is executed by Python 3 before
|
|
|
|
|
the ``elle`` module has been converted).
|
|
|
|
|
|
|
|
|
|
In that case, it's not much more difficult to write a little code to
|
2011-04-13 15:21:13 -04:00
|
|
|
|
parse the ``__version__`` from the file rather than importing it.
|
|
|
|
|
Without providing too much detail, it's likely that modules such as
|
|
|
|
|
``distutils2`` will provide a way to parse version strings from files.
|
|
|
|
|
E.g.::
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
2011-04-13 15:21:13 -04:00
|
|
|
|
from distutils2 import get_version
|
2011-04-05 14:47:18 -04:00
|
|
|
|
setup(name='elle', version=get_version('elle.py'))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Distutils2
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
|
|
Because the distutils2 style ``setup.cfg`` is declarative, we can't
|
|
|
|
|
run any code to extract the ``__version__`` attribute, either via
|
2012-05-03 14:30:48 -04:00
|
|
|
|
import or via parsing.
|
|
|
|
|
|
|
|
|
|
In consultation with the distutils-sig [9]_, two options are
|
|
|
|
|
proposed. Both entail containing the version number in a file, and
|
|
|
|
|
declaring that file in the ``setup.cfg``. When the entire contents of
|
|
|
|
|
the file contains the version number, the ``version-file`` key will be
|
|
|
|
|
used::
|
|
|
|
|
|
|
|
|
|
[metadata]
|
|
|
|
|
version-file: version.txt
|
|
|
|
|
|
|
|
|
|
When the version number is contained within a larger file, e.g. of
|
|
|
|
|
Python code, such that the file must be parsed to extract the version,
|
|
|
|
|
the key ``version-from-file`` will be used::
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
|
|
|
|
[metadata]
|
|
|
|
|
version-from-file: elle.py
|
|
|
|
|
|
2011-06-07 17:17:29 -04:00
|
|
|
|
A parsing method similar to that described above will be performed on
|
2011-04-05 14:47:18 -04:00
|
|
|
|
the file named after the colon. The exact recipe for doing this will
|
|
|
|
|
be discussed in the appropriate distutils2 development forum.
|
|
|
|
|
|
|
|
|
|
An alternative is to only define the version number in ``setup.cfg``
|
|
|
|
|
and use the ``pkgutil`` module [8]_ to make it available
|
|
|
|
|
programmatically. E.g. in ``elle.py``::
|
|
|
|
|
|
|
|
|
|
from distutils2._backport import pkgutil
|
|
|
|
|
__version__ = pkgutil.get_distribution('elle').metadata['version']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PEP 376 metadata
|
|
|
|
|
================
|
|
|
|
|
|
2022-01-21 06:03:51 -05:00
|
|
|
|
:pep:`376` defines a standard for static metadata, but doesn't
|
2011-04-05 14:47:18 -04:00
|
|
|
|
describe the process by which this metadata gets created. It is
|
|
|
|
|
highly desirable for the derived version information to be placed into
|
2022-01-21 06:03:51 -05:00
|
|
|
|
the :pep:`376` ``.dist-info`` metadata at build-time rather than
|
2011-04-05 14:47:18 -04:00
|
|
|
|
install-time. This way, the metadata will be available for
|
|
|
|
|
introspection even when the code is not installed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
.. [1] Distutils2 documentation
|
|
|
|
|
(http://distutils2.notmyidea.org/)
|
|
|
|
|
|
|
|
|
|
.. [2] The Cheeseshop (Python Package Index)
|
|
|
|
|
(http://pypi.python.org)
|
|
|
|
|
|
|
|
|
|
.. [3] http://docs.python.org/distutils/setupscript.html
|
|
|
|
|
|
|
|
|
|
.. [5] sqlite3 module documentation
|
|
|
|
|
(http://docs.python.org/library/sqlite3.html)
|
|
|
|
|
|
|
|
|
|
.. [8] pkgutil - Package utilities
|
|
|
|
|
(http://distutils2.notmyidea.org/library/pkgutil.html)
|
|
|
|
|
|
2017-06-11 15:02:39 -04:00
|
|
|
|
.. [9] https://mail.python.org/pipermail/distutils-sig/2011-June/017862.html
|
2012-05-03 14:30:48 -04:00
|
|
|
|
|
2021-04-14 18:08:26 -04:00
|
|
|
|
.. [11] importlib.metadata
|
|
|
|
|
(https://docs.python.org/3/library/importlib.metadata.html#distribution-versions)
|
|
|
|
|
|
2011-04-05 14:47:18 -04:00
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|