是否有一种标准的方法将版本字符串与Python包相关联,以便我可以执行以下操作?

import foo
print(foo.version)

我认为有一些方法可以在没有任何额外硬编码的情况下检索数据,因为minor/major字符串已经在setup.py中指定了。我发现的替代解决方案是在我的foo/__init__.py中导入__version__,然后由setup.py生成__version__.py。


当前回答

只使用VERSION .py文件,文件中有__version__ = <VERSION>参数。在setup.py文件中导入__version__参数,并将其值放在setup.py文件中,如下所示: version = __version__ 另一种方法是只使用version=<CURRENT_VERSION>的setup.py文件- CURRENT_VERSION是硬编码的。

因为我们不希望每次创建一个新标记(准备发布一个新的包版本)时都手动更改文件中的版本,所以我们可以使用以下..

我强烈推荐凸版包。多年来我一直在用它来撞一个版本。

首先在setup.py文件中添加version=< version >,如果你还没有的话。

你应该在每次碰到一个版本时使用这样一个简短的脚本:

bumpversion (patch|minor|major) - choose only one option
git push
git push --tags

然后为每个repo添加一个名为.bumpversion.cfg的文件:

[bumpversion]
current_version = <CURRENT_TAG>
commit = True
tag = True
tag_name = {new_version}
[bumpversion:file:<RELATIVE_PATH_TO_SETUP_FILE>]

注意:

你可以像在其他文章中建议的那样,在version.py文件下使用__version__参数,并像这样更新bumpversion文件: [bumpversion:文件:< RELATIVE_PATH_TO_VERSION_FILE >) 你必须git提交或git重置你的回购中的所有东西,否则你会得到一个肮脏的回购错误。 确保你的虚拟环境包含了bump版本的包,没有它它将无法工作。

其他回答

我在这里描述了一种标准的现代方法,它依赖于setuptools_scm。 在过去的几年中,这种模式已经成功地应用于许多已发布的包,因此我强烈推荐它。

注意,您不需要getversion包来实现这个模式。getversion文档恰好包含这个技巧。

同样值得注意的是,__version__是一个半std。在python中,__version_info__也是一个元组,在简单的情况下,你可以这样做:

__version__ = '1.2.3'
__version_info__ = tuple([ int(num) for num in __version__.split('.')])

...你可以从文件或其他地方获取__version__字符串。

在python包中嵌入版本字符串似乎没有标准的方法。我见过的大多数包都使用您的解决方案的一些变体,即eitner

将版本嵌入到setup.py中,并让setup.py生成一个只包含版本信息的模块(例如version.py),该模块由你的包导入,或者 相反:把版本信息放在你的包中,然后在setup.py中导入它来设置版本

这里的许多解决方案都忽略了git版本标签,这仍然意味着你必须在多个地方跟踪版本(不好)。我的目标如下:

从git repo中的一个标记中派生所有python版本引用 自动化git标记/推送和setup.py上传步骤,只需一个命令,无需输入。

工作原理:

从make release命令中,找到git repo中最后一个带标记的版本并对其进行递增。标签被推回到原点。 Makefile将版本存储在src/_version.py中,它将被setup.py读取,并包含在发布版中。不要将_version.py检入源代码控制! Setup.py命令从package.__version__中读取新的版本字符串。

细节:

Makefile

# remove optional 'v' and trailing hash "v1.0-N-HASH" -> "v1.0-N"
git_describe_ver = $(shell git describe --tags | sed -E -e 's/^v//' -e 's/(.*)-.*/\1/')
git_tag_ver      = $(shell git describe --abbrev=0)
next_patch_ver = $(shell python versionbump.py --patch $(call git_tag_ver))
next_minor_ver = $(shell python versionbump.py --minor $(call git_tag_ver))
next_major_ver = $(shell python versionbump.py --major $(call git_tag_ver))

.PHONY: ${MODULE}/_version.py
${MODULE}/_version.py:
    echo '__version__ = "$(call git_describe_ver)"' > $@

.PHONY: release
release: test lint mypy
    git tag -a $(call next_patch_ver)
    $(MAKE) ${MODULE}/_version.py
    python setup.py check sdist upload # (legacy "upload" method)
    # twine upload dist/*  (preferred method)
    git push origin master --tags

发行版目标总是增加第3个版本的数字,但是您可以使用next_minor_ver或next_major_ver来增加其他数字。这些命令依赖于签入repo根目录的versionbump.py脚本

versionbump.py

"""An auto-increment tool for version strings."""

import sys
import unittest

import click
from click.testing import CliRunner  # type: ignore

__version__ = '0.1'

MIN_DIGITS = 2
MAX_DIGITS = 3


@click.command()
@click.argument('version')
@click.option('--major', 'bump_idx', flag_value=0, help='Increment major number.')
@click.option('--minor', 'bump_idx', flag_value=1, help='Increment minor number.')
@click.option('--patch', 'bump_idx', flag_value=2, default=True, help='Increment patch number.')
def cli(version: str, bump_idx: int) -> None:
    """Bumps a MAJOR.MINOR.PATCH version string at the specified index location or 'patch' digit. An
    optional 'v' prefix is allowed and will be included in the output if found."""
    prefix = version[0] if version[0].isalpha() else ''
    digits = version.lower().lstrip('v').split('.')

    if len(digits) > MAX_DIGITS:
        click.secho('ERROR: Too many digits', fg='red', err=True)
        sys.exit(1)

    digits = (digits + ['0'] * MAX_DIGITS)[:MAX_DIGITS]  # Extend total digits to max.
    digits[bump_idx] = str(int(digits[bump_idx]) + 1)  # Increment the desired digit.

    # Zero rightmost digits after bump position.
    for i in range(bump_idx + 1, MAX_DIGITS):
        digits[i] = '0'
    digits = digits[:max(MIN_DIGITS, bump_idx + 1)]  # Trim rightmost digits.
    click.echo(prefix + '.'.join(digits), nl=False)


if __name__ == '__main__':
    cli()  # pylint: disable=no-value-for-parameter

这就完成了如何从git处理和增加版本号的繁重工作。

__init__ . py

my_module/_version.py文件被导入到my_module/__init__.py。将您希望随模块一起分发的任何静态安装配置放在这里。

from ._version import __version__
__author__ = ''
__email__ = ''

setup . py

最后一步是从my_module模块中读取版本信息。

from setuptools import setup, find_packages

pkg_vars  = {}

with open("{MODULE}/_version.py") as fp:
    exec(fp.read(), pkg_vars)

setup(
    version=pkg_vars['__version__'],
    ...
    ...
)

当然,要让所有这些工作,你必须在你的回购中至少有一个版本标签才能开始。

git tag -a v0.0.1

使用setuptools和pyproject.toml

Setuptools现在提供了一种动态获取pyproject.toml版本的方法

重现这里的示例,您可以在pyproject.toml中创建如下内容

# ...
[project]
name = "my_package"
dynamic = ["version"]
# ...
[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"}