是否有一种标准的方法将版本字符串与Python包相关联,以便我可以执行以下操作?
import foo
print(foo.version)
我认为有一些方法可以在没有任何额外硬编码的情况下检索数据,因为minor/major字符串已经在setup.py中指定了。我发现的替代解决方案是在我的foo/__init__.py中导入__version__,然后由setup.py生成__version__.py。
是否有一种标准的方法将版本字符串与Python包相关联,以便我可以执行以下操作?
import foo
print(foo.version)
我认为有一些方法可以在没有任何额外硬编码的情况下检索数据,因为minor/major字符串已经在setup.py中指定了。我发现的替代解决方案是在我的foo/__init__.py中导入__version__,然后由setup.py生成__version__.py。
当前回答
使用setuptools和pyproject.toml
Setuptools现在提供了一种动态获取pyproject.toml版本的方法
重现这里的示例,您可以在pyproject.toml中创建如下内容
# ...
[project]
name = "my_package"
dynamic = ["version"]
# ...
[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"}
其他回答
我在包目录中使用了一个JSON文件。这符合Zooko的要求。
内部pkg_dir / pkg_info.json:
{"version": "0.1.0"}
在setup . py:
from distutils.core import setup
import json
with open('pkg_dir/pkg_info.json') as fp:
_info = json.load(fp)
setup(
version=_info['version'],
...
)
内部pkg_dir / __init__ . py:
import json
from os.path import dirname
with open(dirname(__file__) + '/pkg_info.json') as fp:
_info = json.load(fp)
__version__ = _info['version']
我还在pkg_info中放入了其他信息。Json,比如author。我 我喜欢使用JSON,因为我可以自动管理元数据。
重写2017 - 05
在写了13年以上的Python代码和管理各种包之后,我得出的结论是,DIY可能不是最好的方法。
我开始使用pbr包来处理包中的版本控制。如果您正在使用git作为您的SCM,这将像魔法一样适合您的工作流,节省您数周的工作时间(您将惊讶于问题的复杂程度)。
截至目前,pbr的月下载量为1200万次,达到这一水平并不需要任何肮脏的手段。这只是一件事——用非常简单的方法解决一个常见的包装问题。
PBR可以承担更多的包维护负担,而且不局限于版本控制,但它不会强迫您采用它的所有好处。
所以为了给你一个关于如何在一次提交中采用策略br的想法,看看切换包装到策略br
您可能会注意到版本根本没有存储在存储库中。PBR确实从Git分支和标记中检测到它。
不需要担心没有git存储库时会发生什么,因为在打包或安装应用程序时,pbr会“编译”并缓存版本,因此不依赖于git的运行时。
旧的解决方案
以下是我迄今为止见过的最好的解决方案,它也解释了为什么:
借“yourpackage / version.py:
# Store the version here so:
# 1) we don't load dependencies by storing it in __init__.py
# 2) we can import it in setup.py for the same reason
# 3) we can import it into your module module
__version__ = '0.12'
内部yourpackage / __init__ . py:
from .version import __version__
在setup . py:
exec(open('yourpackage/version.py').read())
setup(
...
version=__version__,
...
如果你知道其他更好的方法,请告诉我。
经过几个小时的努力,我找到了最简单可靠的解决方案,以下是其中的几个部分:
在你的包"/mypackage"文件夹中创建一个version.py文件:
# Store the version here so:
# 1) we don't load dependencies by storing it in __init__.py
# 2) we can import it in setup.py for the same reason
# 3) we can import it into your module module
__version__ = '1.2.7'
在setup . py:
exec(open('mypackage/version.py').read())
setup(
name='mypackage',
version=__version__,
在主文件夹init.py中:
from .version import __version__
exec()函数在任何导入之外运行脚本,因为在导入模块之前运行setup.py。您仍然只需要在一个地方的一个文件中管理版本号,但不幸的是,它不在setup.py中。(这是缺点,但没有导入错误是优点)
《绿箭侠》以一种有趣的方式处理它。
现在(2e5031b起)
在箭头/ __init__ . py:
__version__ = 'x.y.z'
在setup . py:
from arrow import __version__
setup(
name='arrow',
version=__version__,
# [...]
)
之前
在箭头/ __init__ . py:
__version__ = 'x.y.z'
VERSION = __version__
在setup . py:
def grep(attrname):
pattern = r"{0}\W*=\W*'([^']+)'".format(attrname)
strval, = re.findall(pattern, file_text)
return strval
file_text = read(fpath('arrow/__init__.py'))
setup(
name='arrow',
version=grep('__version__'),
# [...]
)
根据延迟的[STOP PRESS: rejected] PEP 396(模块版本号),有一种建议的方法来做到这一点。它描述了模块遵循的基本原理(当然是可选的)标准。下面是一个片段:
当模块(或包)包含版本号时,该版本应该在__version__属性中可用。
对于位于命名空间包中的模块,模块应该包含__version__属性。命名空间包本身不应该包含自己的__version__属性。
__version__属性的值应该是一个字符串。