Home > Mobile >  Adding version attribute to Python module
Adding version attribute to Python module

Time:05-09

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.

  • Related