What is the correct way to share package version with setup.py and the package?
Set the version in setup.py
only, and read your own version with pkg_resources
, effectively querying the setuptools
metadata:
file: setup.py
setup(
name='foobar',
version='1.0.0',
# other attributes
)
file: __init__.py
from pkg_resources import get_distribution
__version__ = get_distribution('foobar').version
To make this work in all cases, where you could end up running this without having installed it, test for DistributionNotFound
and the distribution location:
from pkg_resources import get_distribution, DistributionNotFound
import os.path
try:
_dist = get_distribution('foobar')
# Normalize case for Windows systems
dist_loc = os.path.normcase(_dist.location)
here = os.path.normcase(__file__)
if not here.startswith(os.path.join(dist_loc, 'foobar')):
# not installed, but there is another version that *is*
raise DistributionNotFound
except DistributionNotFound:
__version__ = 'Please install this project with setup.py'
else:
__version__ = _dist.version
I don't believe there's a canonical answer to this, but my method (either directly copied or slightly tweaked from what I've seen in various other places) is as follows:
Folder heirarchy (relevant files only):
package_root/
|- main_package/
| |- __init__.py
| `- _version.py
`- setup.py
main_package/_version.py
:
"""Version information."""
# The following line *must* be the last in the module, exactly as formatted:
__version__ = "1.0.0"
main_package/__init__.py
:
"""Something nice and descriptive."""
from main_package.some_module import some_function_or_class
# ... etc.
from main_package._version import __version__
__all__ = (
some_function_or_class,
# ... etc.
)
setup.py
:
from setuptools import setup
setup(
version=open("main_package/_version.py").readlines()[-1].split()[-1].strip("\"'"),
# ... etc.
)
... which is ugly as sin ... but it works, and I've seen it or something like it in packages distributed by people who I'd expect to know a better way if there were one.