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

import foo
print(foo.version)

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


当前回答

重写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__,
    ...

如果你知道其他更好的方法,请告诉我。

其他回答

无论如何,如果你使用NumPy distutils, NumPy .distutils.misc_util。Configuration有一个make_svn_version_py()方法,它将版本号嵌入到包中。变量version中的__svn_version__。

《绿箭侠》以一种有趣的方式处理它。

现在(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__'),
    # [...]
)

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

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

如果您使用CVS(或RCS)并想要快速解决方案,您可以使用:

__version__ = "$Revision: 1.1 $"[11:-2]
__version_info__ = tuple([int(s) for s in __version__.split(".")])

(当然,修订号会被CVS代替)

这为您提供了一个打印友好的版本和版本信息,您可以使用它来检查您正在导入的模块至少具有预期的版本:

import my_module
assert my_module.__version_info__ >= (1, 1)

我更喜欢从安装环境中读取包版本。 这是我的src/foo/_version.py:

from pkg_resources import get_distribution                                        
                                                                                  
__version__ = get_distribution('foo').version

确保foo总是已经安装,这就是为什么需要src/ layer来防止在没有安装的情况下导入foo。

在setup.py中,我使用setuptools-scm自动生成版本。


2022.7.5更新:

还有另一种方法,这是我现在最喜欢的。使用setuptools-scm生成_version.py文件。

setup(
    ...
    use_scm_version={
        'write_to':
        'src/foo/_version.py',
        'write_to_template':
        '"""Generated version file."""\n'
        '__version__ = "{version}"\n',
    },
)