Single source of truth for Python project version in presence of pyproject.toml
Question:
The pyproject.toml specification affords the ability to specify the project version, e.g.
[project]
name = "foo"
version = "0.0.1"
However, it is also a common Python idiom to put __version__ = "0.0.1"
in foo/__init__.py
so that users can query it.
Is there a standard way of extracting the version
from the pyproject.toml
and getting it into the foo/__init__.py
?
Answers:
There are two approaches you can take here.
-
Keep version in pyproject.toml
and get it from the package metadata in the source code. So, in your foo/__init__.py
or wherever:
from importlib.metadata import version
__version__ = version(__package__)
importlib.metadata.version
is available since Python 3.8. For earlier Python versions, you can do similar with the importlib_metadata
backport.
-
Keep the version in the source code and instruct the build system to get it from there. For a setuptools build backend, it looks like this in pyproject.toml
:
[project]
dynamic = ["version"]
[tool.setuptools.dynamic]
version = {attr = "foo.__version__"}
My recommendation is actually ( ) … neither! Don’t keep a __version__
attribute in the source code at all. It’s an outdated habit which we can do without these days. Version
is already a required field in the package metadata, it’s redundant to keep the same string as an attribute in the package/module namespace.
The pyproject.toml specification affords the ability to specify the project version, e.g.
[project]
name = "foo"
version = "0.0.1"
However, it is also a common Python idiom to put __version__ = "0.0.1"
in foo/__init__.py
so that users can query it.
Is there a standard way of extracting the version
from the pyproject.toml
and getting it into the foo/__init__.py
?
There are two approaches you can take here.
-
Keep version in
pyproject.toml
and get it from the package metadata in the source code. So, in yourfoo/__init__.py
or wherever:from importlib.metadata import version __version__ = version(__package__)
importlib.metadata.version
is available since Python 3.8. For earlier Python versions, you can do similar with theimportlib_metadata
backport. -
Keep the version in the source code and instruct the build system to get it from there. For a setuptools build backend, it looks like this in
pyproject.toml
:[project] dynamic = ["version"] [tool.setuptools.dynamic] version = {attr = "foo.__version__"}
My recommendation is actually ( ) … neither! Don’t keep a __version__
attribute in the source code at all. It’s an outdated habit which we can do without these days. Version
is already a required field in the package metadata, it’s redundant to keep the same string as an attribute in the package/module namespace.