[Python-Dev] PEP 396, Module Version Numbers (original) (raw)
Barry Warsaw barry at python.org
Tue Apr 5 20:52:13 CEST 2011
- Previous message: [Python-Dev] Buildbot status
- Next message: [Python-Dev] PEP 396, Module Version Numbers
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
I just checked in PEP 396, Module Version Numbers. This is an informational PEP describing how to specify version numbers using the version attribute. This has already made one round through distutils-sig so it's time to post it here. Comments welcome of course!
Cheers, -Barry
P.S. Yeah, I know the KeywordKeywordKeyword strings here are wrong. I'm not sure what to do about them though.
PEP: 396 Title: Module Version Numbers Version: Revision:65628Revision: 65628 Revision:65628 Last-Modified: Date:2008−08−1009:59:20−0400(Sun,10Aug2008)Date: 2008-08-10 09:59:20 -0400 (Sun, 10 Aug 2008) Date:2008−08−1009:59:20−0400(Sun,10Aug2008) Author: Barry Warsaw <barry at python.org> Status: Draft Type: Informational Content-Type: text/x-rst Created: 2011-03-16 Post-History: 2011-04-05
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.
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.
Carole maintains several namespace packages, each of which are
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
de-facto standards for describing version numbers, and many ad-hoc
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
release's version number can be specified. PEP 8 [4]_ describes the
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.
Another example of version information is the sqlite3 [5]_ library
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.
#. When a module includes a version number, it SHOULD be available in
the __version__
attribute on that module.
#. For modules which are also packages, the module namespace SHOULD
include the __version__
attribute.
#. For modules which live inside a namespace package, the sub-package
name SHOULD include the __version__
attribute. The namespace
module itself SHOULD NOT include its own __version__
attribute.
#. The __version__
attribute's value SHOULD be a string.
#. Module version numbers SHOULD conform to the normalized version format specified in PEP 386 [6]_.
#. 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).
#. Wherever a __version__
attribute exists, a module MAY also
include a __version_info__
attribute, containing a tuple
representation of the module version number, for easy comparisons.
#. __version_info__
SHOULD be of the format returned by PEP 386's
parse_version()
function.
#. The version
attribute in a classic distutils setup.py
file, or the PEP 345 [7]_ Version
metadata field SHOULD be
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.
While there are any number of ways this could be done, this section describes one possible approach, for each scenario.
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
parse the __version__
from the file rather than importing it::
import re
DEFAULT_VERSION_RE = re.compile(r'(?P<version>\d+\.\d(?:\.\d+)?)')
def get_version(filename, pattern=None):
if pattern is None:
cre = DEFAULT_VERSION_RE
else:
cre = re.compile(pattern)
with open(filename) as fp:
for line in fp:
if line.startswith('__version__'):
mo = cre.search(line)
assert mo, 'No valid __version__ string found'
return mo.group('version')
raise AssertionError('No __version__ assignment found')
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
import or via parsing. This PEP suggests a special key be added to
the [metadata]
section of the setup.cfg
file to indicate "get
the version from this file". Something like this might work::
[metadata]
version-from-file: elle.py
where parse
means to use a parsing method similar to the above, on
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
PEP 376 [9]_ defines a standard for static metadata, but doesn't
describe the process by which this metadata gets created. It is
highly desirable for the derived version information to be placed into
the PEP 376 .dist-info
metadata at build-time rather than
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
.. [4] PEP 8, Style Guide for Python Code (http://www.python.org/dev/peps/pep-0008)
.. [5] sqlite3 module documentation (http://docs.python.org/library/sqlite3.html)
.. [6] PEP 386, Changing the version comparison module in Distutils (http://www.python.org/dev/peps/pep-0386/)
.. [7] PEP 345, Metadata for Python Software Packages 1.2 (http://www.python.org/dev/peps/pep-0345/#version)
.. [8] pkgutil - Package utilities (http://distutils2.notmyidea.org/library/pkgutil.html)
.. [9] PEP 376, Database of Installed Python Distributions (http://www.python.org/dev/peps/pep-0376/)
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: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: not available URL: <http://mail.python.org/pipermail/python-dev/attachments/20110405/d3726374/attachment.pgp>
- Previous message: [Python-Dev] Buildbot status
- Next message: [Python-Dev] PEP 396, Module Version Numbers
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]