我不知道为什么其他答案说你的方法不推荐,相反地,它是官方推荐的(截至2023年)。Python核心开发人员使用这种方法。你需要确保的是以__version__
字符串的形式静态地而非动态地定义它(即不要在运行时从文本文件中获取,它必须硬编码在Python文件的一个Python字符串中,在构建时静态可用)。
自 setuptools v61 起, 你确实可以在你的包的__init__.py
文件中设置一个__version__
属性,就像你所做的那样,然后在pyproject.toml
中动态获取它,如下所示:
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"
[project]
name = ["mypackage"]
dynamic = ["version"]
[tool.setuptools.dynamic]
version = {attr = "mypackage.__version__"}
请注意,如果您希望从
mypackage
内部访问
mypackage.__version__
,则不应该使用
from . import __version__
,因为如果您还在
__init__.py
中导入其他内容,这将导致无限循环导入!相反,您需要实现一个函数来
读取(而不是导入!)
__init__.py
并提取版本字符串,幸运的是,官方文档现在提供了
一个简单的示例。
import codecs
import os.path
def read(rel_path):
here = os.path.abspath(os.path.dirname(__file__))
with codecs.open(os.path.join(here, rel_path), 'r') as fp:
return fp.read()
def get_version(rel_path):
for line in read(rel_path).splitlines():
if line.startswith('__version__'):
delim = '"' if '"' in line else "'"
return line.split(delim)[1]
else:
raise RuntimeError("Unable to find version string.")
version = get_version("mypackage/__init__.py")
如果您只想支持 Py3,那么一切都准备就绪,您可以停止阅读了。
但是,如果您需要使用旧版本的 setuptools,例如需要支持 Python 2.7(这是非常不建议的,但某些遗留项目可能需要),那么您可以使用支持动态版本的 setup.cfg,因为较早的 setuptools 版本开始支持它。
[metadata]
name = mypackage
version = attr: mypackage.__version__
请注意,您仍然需要一个几乎为空的
setup.py
,以使
setup.cfg
起作用,否则setuptools将无法正常工作(这是
官方规定)。
from setuptools import setup
setup()
但是,如果您还希望您的模块既有一个 setup.cfg 和 setup.py 来支持 Py2,又有一个 pyproject.toml 来支持 Py3,那么您会注意到在 Py2 下构建可能会失败,因为需要一个版本太高的 setuptools(Py2 上最新版本为 v41.1.1)。实际上,即使在 Py2 下构建是通过 setup.cfg 和 setup.py 完成的,如果您更新了 pip,它仍然会访问 pyproject.toml 并访问 [build-system] 表,因为这是一个模块可以指定构建时需求的唯一位置,根据 PEP 517 的规定。
要解决这个问题,您需要编辑 pyproject.toml 中的构建要求,以指定 Python 版本(关于依赖规范,请参阅 PEP 508 的
链接)。
[build-system]
requires = ["setuptools>=44;python_version<'3'", "setuptools>=61;python_version>='3'"]
build-backend = "setuptools.build_meta"
然后你的软件包应该能够正常构建(使用
build
模块或
pip install --pep-517
),在Py3和Py2下都可以,前者只需使用pyproject.toml,后者则需要使用setup.cfg(同时还需要一点pyproject.toml来配置构建系统)。
pyproject.toml
和setup.py
?你应该只使用其中一个。 - wim