Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ModuleNotFoundError when using setup.cfg and version accessed with attr

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?

like image 842
Neraste Avatar asked Oct 02 '19 13:10

Neraste


1 Answers

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.

like image 147
sinoroc Avatar answered Oct 19 '22 03:10

sinoroc