Skip to content

Commit 0400251

Browse files
committed
Misc edits
* address review comments * go back to semantic cross-references (the build will fail until the CPython PR and its backports land, but that's OK)
1 parent f8aa29b commit 0400251

File tree

2 files changed

+44
-23
lines changed

2 files changed

+44
-23
lines changed

source/discussions/single-source-version.rst

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,40 @@ Single-sourcing the Project Version
1010
Many Python :term:`distribution packages <Distribution Package>` publish a single
1111
Python :term:`import package <Import Package>` where it is desired that the runtime
1212
``__version__`` attribute on the import package report the same version specifier
13-
as ``importlib.metadata.version`` reports for the distribution package
13+
as :func:`importlib.metadata.version` reports for the distribution package
1414
(as described in :ref:`runtime-version-access`).
1515

1616
It is also frequently desired that this version information be derived from a version
1717
control system *tag* (such as ``v1.2.3``) rather than being manually updated in the
1818
source code.
1919

20-
To ensure that version numbers do not get out of sync, it may be sufficient to add
21-
an automated test case that ensures ``package.__version__`` and
22-
``importlib.metadata.version("package")`` report the same value.
20+
Some projects may choose to simply live with the data entry duplication, and rely
21+
on automated testing to ensure the different values do not diverge.
2322

2423
Alternatively, a project's chosen build system may offer a way to define a single
2524
source of truth for the version number.
2625

2726
In general, the options are:
2827

29-
1) If the code is in a version control system (VCS), e.g. Git, then the version can be extracted from the VCS.
28+
1) If the code is in a version control system (VCS), such as Git, then the version can be extracted from the VCS.
3029

3130
2) The version can be hard-coded into the :file:`pyproject.toml` file -- and the build system can copy it
3231
into other locations it may be required.
3332

3433
3) The version string can be hard-coded into the source code -- either in a special purpose file,
35-
such as :file:`_version.txt`, or as an attribute in a module, such as :file:`__init__.py`, and the build
36-
system can extract it at build time.
34+
such as :file:`_version.txt` (which must then be shipped as part of the project's source distribution
35+
package), or as an attribute in a particular module, such as :file:`__init__.py`. The build
36+
system can then extract it from the runtime location at build time.
3737

3838
Consult your build system's documentation for their recommended method.
3939

40+
When the intention is that a distribution package and its associated import package
41+
share the same version, it is recommended that the project include an automated test
42+
case that ensures ``import_name.__version__`` and ``importlib.metadata.version("dist-name")``
43+
report the same value (note: for many projects, ``import_name`` and ``dist-name`` will
44+
be the same name).
45+
46+
4047
.. _Build system version handling:
4148

4249
Build System Version Handling

source/discussions/versioning.rst

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,42 +178,47 @@ Accessing version information at runtime
178178

179179
Version information for all :term:`distribution packages <Distribution Package>`
180180
that are locally available in the current environment can be obtained at runtime
181-
using the standard library's ``importlib.metadata.version`` function::
181+
using the standard library's :func:`importlib.metadata.version` function::
182182

183183
>>> importlib.metadata.version("pip")
184184
'23.3.2'
185185

186-
Many libraries also choose to version their top level
186+
Many projects also choose to version their top level
187187
:term:`import packages <Import Package>` by providing a package level
188188
``__version__`` attribute::
189189

190-
>>> import pip
191-
>>> pip.__version__
192-
'23.3.2'
190+
>>> import cryptography
191+
>>> cryptography.__version__
192+
'41.0.7'
193193

194-
Import packages are *not* required to be versioned independently of their
195-
distribution package version information (see the rejected proposal in
196-
:pep:`PEP 396 <396>`), so this approach to retrieving runtime version
197-
information should only be used with libraries that are known to provide it.
194+
This technique can be particularly valuable for CLI applications which want
195+
to ensure that version query invocations (such as ``pip -V``) run as quickly
196+
as possible.
198197

199-
Library publishers wishing to ensure their reported distribution package and
198+
Package publishers wishing to ensure their reported distribution package and
200199
import package versions are consistent with each other can review the
201200
:ref:`single-source-version` discussion for potential approaches to doing so.
202201

203-
Some libraries may need to publish version information for external APIs
202+
However, as import packages and modules are not *required* to publish runtime
203+
version information in this way (see the rejected proposal in
204+
:pep:`PEP 396 <396>`), the ``__version__`` attribute should either only be
205+
queried with interfaces that are known to provide it, or else the querying
206+
code should be designed to handle the case where the attribute is missing
207+
[#fallback-to-dist-version]_.
208+
209+
Some projects may need to publish version information for external APIs
204210
that don't meet the requirements for Python distribution package
205-
:ref:`version specifiers <version-specifiers>`. Such libraries should
206-
define their own library-specific ways of obtaining the relevant information
211+
:ref:`version specifiers <version-specifiers>`. Such projects should
212+
define their own project-specific ways of obtaining the relevant information
207213
at runtime. For example, the standard library's :mod:`ssl` module offers
208214
multiple ways to access the underlying OpenSSL library version::
209215

210216
>>> ssl.OPENSSL_VERSION
211217
'OpenSSL 3.2.2 4 Jun 2024'
212218
>>> ssl.OPENSSL_VERSION_INFO
213219
(3, 2, 0, 2, 0)
214-
>>> ssl.OPENSSL_VERSION_NUMBER
215-
807403552
216-
220+
>>> hex(ssl.OPENSSL_VERSION_NUMBER)
221+
'0x30200020'
217222

218223
--------------------------------------------------------------------------------
219224

@@ -226,6 +231,15 @@ multiple ways to access the underlying OpenSSL library version::
226231
Brett Cannon <semver-brett-cannon_>`_. For a humoristic take, read about
227232
ZeroVer_.
228233
234+
.. [#fallback-to-dist-version] A full list mapping the top level names available
235+
for import to the distribution packages that provide those import packages and
236+
modules may be obtained through the standard library's
237+
:func:`importlib.metadata.packages_distributions` function. This means that
238+
even code that is attempting to infer a version to report for all importable
239+
top-level names has a means to fall back to reporting the distribution
240+
version information if no ``__version__`` attribute is defined. Only standard
241+
library modules, and modules added via means other than Python package
242+
installation would fail to have version information reported in that case.
229243
230244
231245
.. _zerover: https://0ver.org

0 commit comments

Comments
 (0)