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

Ner*_*ste 6 setuptools setup.py python-3.x

我有一个具有以下结构的 Python 包:

??? setup.cfg
??? setup.py
??? src
    ??? myproject
        ??? base.py
        ??? __init__.py
        ??? version.py
Run Code Online (Sandbox Code Playgroud)

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

[metadata]
name = myproject
version = attr: myproject.version.__version__
Run Code Online (Sandbox Code Playgroud)

随着version.py被简单地说:

[metadata]
name = myproject
version = attr: myproject.version.__version__
Run Code Online (Sandbox Code Playgroud)

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

__version__ = "1.2.3"
Run Code Online (Sandbox Code Playgroud)

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

现在的问题是,如果我python setup.py在未安装依赖项时尝试使用,我有一个ModuleNotFoundError/ ImportError,因为__init__.py导入了导入这些依赖项的对象(这对于管理版本文件的 Python 文档中的案例 6 非常重要):

from myproject.base import Stuff

__all__ = ["Stuff"]
Run Code Online (Sandbox Code Playgroud)

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

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

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

有没有更好的办法?还是另一种方法?

sin*_*roc 5

看起来您遇到了此处提交的问题:https : //github.com/pypa/setuptools/issues/1724

你最好在 a 中写入你的版本号,VERSION.txt从setup.cfgwith读取它version = file: VERSION.txt,然后从你的__init__.pywith加载它import importlib_metadata; __version__ = importlib_metadata.version('myproject')。


更新

该软件包importlib_metadata位于 PyPI 上,适用于当前的 Python 版本,从标准库中的Python 3.8importlib.metadata开始,作为.

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

或者,我倾向于让我的安装脚本从更改日志中读取版本字符串。


2020 年 11 月 3 日更新:

attr:由于这一变化,情况似乎同时有所改善。如果可能, usingattr:实际上不会导入代码,因此问题中ModuleNotFoundError最初报告的内容不应再发生。它已经发布了v46.4.0于2020年5月16日。

  • 这非常优雅地解决了这个问题。附带说明一下,“importlib_metadata”是您必须安装的第三方软件包。从 Python 3.8 开始,它将作为“importlib.metadata”成为标准库的一部分。 (2认同)