我有一个具有以下结构的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
导入导入这些依赖项的对象(这与Python文档中关于管理版本文件的情况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.txt
从setup.cfg
读取它,然后用import importlib_metadata; __version__ = importlib_metadata.version('myproject')
从你的__init__.py
加载它。
更新
包importlib_metadata
在当前 Python 版本的 PyPI 上,从标准库中的Python 3.8开始作为importlib.metadata
。
综上所述,可以重新考虑将版本字符串放在单独文件中的必要性。由于有一种从代码中读取版本字符串的简单方法,因此可能会丢失version.py
或VERSION.txt
的目的。
或者,我倾向于让我的安装脚本从更改日志中读取版本字符串。
更新 2020年11月3日:
由于这一变化,看起来attr:
的情况同时有所改善。如果可能,使用attr:
实际上不会导入代码,因此问题中最初报告ModuleNotFoundError
应该不再发生。它已于2020 年 5 月 16 日在v46.4.0中发布。