我同意@stefano-m关于以下方面的哲学:
在源代码中有version = "xyz" 并在 setup.py 中解析它绝对是正确的解决方案,恕我直言。比(反过来)依赖运行时魔法要好得多。
这个答案来自@zero-piraeus 的答案。重点是“不要在 setup.py 中使用导入,而是从文件中读取版本”。
我使用正则表达式来解析它,__version__
因此它根本不需要是专用文件的最后一行。事实上,我仍然将单一真相源__version__
放在我项目的__init__.py
.
文件夹层次结构(仅相关文件):
package_root/
|- main_package/
| `- __init__.py
`- setup.py
main_package/__init__.py
:
# You can have other dependency if you really need to
from main_package.some_module import some_function_or_class
# Define your version number in the way you mother told you,
# which is so straightforward that even your grandma will understand.
__version__ = "1.2.3"
__all__ = (
some_function_or_class,
# ... etc.
)
setup.py
:
from setuptools import setup
import re, io
__version__ = re.search(
r'__version__\s*=\s*[\'"]([^\'"]*)[\'"]', # It excludes inline comment too
io.open('main_package/__init__.py', encoding='utf_8_sig').read()
).group(1)
# The beautiful part is, I don't even need to check exceptions here.
# If something messes up, let the build process fail noisy, BEFORE my release!
setup(
version=__version__,
# ... etc.
)
......这仍然不理想......但它有效。
顺便说一句,此时你可以用这种方式测试你的新玩具:
python setup.py --version
1.2.3
PS:这个官方的 Python 打包文档(及其镜像)描述了更多的选项。它的第一个选项也是使用正则表达式。(取决于您使用的确切正则表达式,它可能会或可能不会处理版本字符串中的引号。但通常不是一个大问题。)
PPS:ADAL Python中的修复现在被反向移植到这个答案中。