With distutils
, setuptools
, etc. a package version is specified in setup.py
:
# file: setup.py
...
setup(
name='foobar',
version='1.0.0',
# other attributes
)
I would like to be able to access the same version number from within the package:
>>> import foobar
>>> foobar.__version__
'1.0.0'
I could add __version__ = '1.0.0'
to my package's __init__.py, but I would also like to include additional imports in my package to create a simplified interface to the package:
# file: __init__.py
from foobar import foo
from foobar.bar import Bar
__version__ = '1.0.0'
and
# file: setup.py
from foobar import __version__
...
setup(
name='foobar',
version=__version__,
# other attributes
)
However, these additional imports can cause the installation of foobar
to fail if they import other packages that are not yet installed. 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 importlib.metadata.version()
, effectively querying the installed package metadata:
file: setup.py
setup(
name='foobar',
version='1.0.0',
# other attributes
)
file: __init__.py
from importlib.metadata import version
__version__ = version('foobar')
To make this work in all cases, where you could end up running this without having installed it, test for PackageNotFoundError
and use importlib.metadata.distribution()
the introspect the distribution location:
from importlib.metadata import distribution, version, PackageNotFoundError
import os.path
try:
_dist = distribution('foobar')
# Normalize case for Windows systems
dist_loc = os.path.normcase(_dist.locate_file(""))
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 PackageNotFoundError
except PackageNotFoundError:
__version__ = 'Please install this project with setup.py'
else:
__version__ = _dist.version