I am building a Python module with a structure like:
mypackage/
mypackage/
__init__.py
etc.py
setup.py
setup.cfg
pyproject.toml
To build it, I am running $ python -m build
. I noticed that version numbers weren't available (e.g. mypackage.__version__
is undefined after installing), and currently I am just setting it manually like:
setup.py
setup(..., version='0.0.1' )
pyproject.toml
[project]
version = '0.0.1'
I am new to Python package development and there are a few posts on this, but there does not seem to be a standard way of doing it.
The package is quite small and ideally I'd like to just update one thing like __version__ = '0.0.1'
inside __init__.py
, and then have this parsed automatically in setup.py
and pyproject.toml
.
CodePudding user response:
Looking at various popular libraries should give some ideas.
One simple way is to parse your __init__.py
inside setup.py
, like this example from the wonderful diff-match-patch library:
with open("diff_match_patch/__init__.py") as f:
for line in f:
if line.startswith("__version__"):
version = line.split('"')[1]
As far as I saw, most of the popular Python projects do not put the version in pyproject.toml
, if they even have it.
Alternately, you could use the nifty versioneer
library, which picks up the version from git. For example, at the time I write this answer, the latest tag in numpy
repository's main
branch history is v1.22.3
, and it is cleanly reflected in numpy.__version__
being 1.22.3
, without practically any work on the numpy
developers' part.
CodePudding user response:
Having a __version__
attribute available in the module namespace is a popular convention, but it's possibly going out of fashion these days since stdlib importlib.metadata
is no longer provisional. The one obvious place for a version string is in the package metadata, duplicating that same version in a module attribute may be considered unnecessary and redundant.
The version string existing in two different places also presents some conundrums for consumers - where should we look for it first, in the package metadata or in a module top-level namespace? And what should we do if the version information found each of these places is different?
So, there is some benefit to only storing it in one place, and that place should be the package's metadata. If you're using a modern build system, then you would specify the version string directly in pyproject.toml
as described in PEP 621 – Storing project metadata in pyproject.toml. The way already shown in the question is correct:
[project]
name = "mypkg"
version = "0.0.1"
Users of mypkg
could retrieve the version like so:
from importlib.metadata import version
version("mypkg")
Note that unlike accessing a __version__
attribute, this version is retrieved from the package metadata only, and the actual package doesn't even need to be imported. That's useful in some cases, e.g. packages which have import side-effects such as numpy, or the ability to retrieve versions of packages even if they have unsatisfied dependencies / complicated environment setup requirements.