使用 setup.cfg 和使用 attr 访问的版本时出现 ModuleNotFoundError

ModuleNotFoundError when using setup.cfg and version accessed with attr

我有一个 Python 包,结构如下:

├── setup.cfg
├── setup.py
└── src
    └── myproject
        ├── base.py
        ├── __init__.py
        └── version.py

setup.cfg中,版本定义为attr:

[metadata]
name = myproject
version = attr: myproject.version.__version__

version.py 相比:

__version__ = "1.2.3"

包具有 setup.cfg 中列出的依赖项。另一方面,包的顶层 __init__.py 导入包的一些对象:

from myproject.base import Stuff

__all__ = ["Stuff"]

而且,显然,base.py 从依赖项中导入了一些对象。

现在的问题是,如果我在未安装依赖项的情况下尝试使用 python setup.py,我会得到一个 ModuleNotFoundError/ImportError,因为 __init__.py 导入对象导入这些依赖项(这非常适用于 the Python documentation on managing version file 中的案例 6):

python setup.py --version
Traceback (most recent call last):
<snip>
ModuleNotFoundError: No module named 'dependency_module'

这使得无法安装依赖项。那么针对版本文件的最佳策略应该是什么?

到目前为止,我已经在 __init__.py 上尝试了这种奇怪的异常处理方法:

try:
    from myproject.base import Stuff
except ImportError:
    pass

有没有更好的方法?或者其他方法?

看起来您 运行 正在处理此处提交的问题:https://github.com/pypa/setuptools/issues/1724

你最好在 VERSION.txt 中写下你的版本号,用 version = file: VERSION.txtsetup.cfg 读取它,然后用 __init__.py 从你的 __init__.py 加载它=14=].


更新

包裹importlib_metadata is on PyPI for current Python versions and starting with Python 3.8 in the standard library as importlib.metadata.

综上所述,可以重新考虑是否需要将版本字符串放在单独的文件中。由于有一种直接的方法可以从代码中读取版本字符串,因此 version.pyVERSION.txt 的目的可能会丢失。

或者我倾向于制作我的设置脚本 read the version string from the changelog


更新 2020 年 11 月 3 日:

看来 attr: 的情况同时有所改善,多亏了这个 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