I have a Python package with the following structure:
├── setup.cfg
├── setup.py
└── src
└── myproject
├── base.py
├── __init__.py
└── version.py
In setup.cfg
, the version is defined with attr
:
[metadata]
name = myproject
version = attr: myproject.version.__version__
With version.py
being simply:
__version__ = "1.2.3"
The package have dependencies listed in setup.cfg
. On the other hand, the package's top level __init__.py
imports some objects of the package:
from myproject.base import Stuff
__all__ = ["Stuff"]
And, obviously, base.py
imports some objects from the dependencies.
The problem is now that if I try to use python setup.py
when the dependencies are not installed, I have a ModuleNotFoundError
/ImportError
, since __init__.py
imports objects importing these dependencies (this is very to case 6 in the Python documentation on managing version file):
python setup.py --version
Traceback (most recent call last):
<snip>
ModuleNotFoundError: No module named 'dependency_module'
which makes installation of the dependencies impossible. So what should be the best strategy to target the version file?
So far, I have tried this weird exception handling approach on __init__.py
:
try:
from myproject.base import Stuff
except ImportError:
pass
Is there a better way? Or another approach?
Looks like you are running into the issue filed here: https://github.com/pypa/setuptools/issues/1724
You'd be better off writing your version number in a VERSION.txt
, read it from setup.cfg
with version = file: VERSION.txt
, and load it from your __init__.py
with import importlib_metadata; __version__ = importlib_metadata.version('myproject')
.
Update
The package importlib_metadata
is on PyPI for current Python versions and starting with Python 3.8 in the standard library as importlib.metadata
.
Now with all that said, the need for having the version string in a separate file could be reconsidered. Since there is a straightforward way to read the version string from within the code, the purpose of version.py
or VERSION.txt
might be lost.
Alternatively I tend to make my setup scripts read the version string from the changelog instead.
Update 3 November 2020:
It looks like the situation with attr:
has improved in the mean time, thanks to this change. If possible, using attr:
does not actually import the code and thus the ModuleNotFoundError
originally reported in the question should not happen anymore. It has been released in v46.4.0 on 16 May 2020.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With