Nico Schlömer
Nico Schlömer

Reputation: 58731

single-sourcing package version for setup.cfg Python projects

For traditional Python projects with a setup.py, there are various ways of ensuring that the version string does not have to be repeated throughout the code base. See PyPA's guide on "Single-sourcing the package version" for a list of recommendations.

Many are trying to move away from setup.py to setup.cfg (probably under the influence of PEP517 and PEP518; setup.py was mostly used declaratively anyway, and when there was logic in setup.py, it was probably for the worse.) This means that most the suggestions won't work anymore since setup.cfg cannot contain "code".

How can I single-source the package version for Python projects that use setup.cfg?

Upvotes: 26

Views: 6483

Answers (1)

sinoroc
sinoroc

Reputation: 22275

There are a couple of ways to do this (see below for the project structure used in these examples):

1.

setup.cfg

[metadata]
version = 1.2.3.dev4

src/my_top_level_package/__init__.py

import importlib.metadata
__version__ = importlib.metadata.version('MyProject')

2.

setup.cfg

[metadata]
version = file: VERSION.txt

VERSION.txt

1.2.3.dev4

src/my_top_level_package/__init__.py

import importlib.metadata
__version__ = importlib.metadata.version('MyProject')

3.

setup.cfg

[metadata]
version = attr: my_top_level_package.__version__

src/my_top_level_package/__init__.py

__version__ = '1.2.3.dev4'

And more...

There are probably other ways to do this, by playing with different combinatons.


References:


Structure assumed in the previous examples is as follows...

MyProject
├── setup.cfg
├── setup.py
└── src
    └── my_top_level_package
        └── __init__.py

setup.py

#!/usr/bin/env python3

import setuptools

if __name__ == '__main__':
    setuptools.setup(
        # see 'setup.cfg'
    )

setup.cfg

[metadata]
name = MyProject
# See above for the value of 'version = ...'

[options]
package_dir =
    = src
packages = find:

[options.packages.find]
where = src
$ cd path/to/MyProject
$ python3 setup.py --version
1.2.3.dev4
$ python3 -m pip install .
# ...
$ python3 -c 'import my_top_level_package; print(my_top_level_package.__version__)'
1.2.3.dev4
$ python3 -V
Python 3.6.9
$ python3 -m pip list
Package       Version   
------------- ----------
MyProject     1.2.3.dev4
pip           20.0.2    
pkg-resources 0.0.0     
setuptools    45.2.0    
wheel         0.34.2    
zipp          3.0.0

Upvotes: 37

Related Questions