Dim*_*iuc 241 python string package
是否有一种标准方法可以将版本字符串与python包关联起来,以便我可以执行以下操作?
import foo
print foo.version
Run Code Online (Sandbox Code Playgroud)
我想有一些方法可以在没有任何额外硬编码的情况下检索数据,因为setup.py已经指定了次要/主要字符串.我找到的替代解决方案是import __version__在我的foo/__init__.py,然后__version__.py生成setup.py.
oef*_*efe 117
不直接回答你的问题,但你应该考虑命名__version__,而不是version.
这几乎是准标准.标准库中的许多模块都使用__version__,这也用于许多第三方模块,因此它是准标准的.
通常,__version__是一个字符串,但有时它也是一个浮点数或元组.
编辑:正如S.Lott所说(谢谢!),PEP 8明确地说:
版本簿记
如果您的源文件中必须包含Subversion,CVS或RCS crud,请按以下步骤操作.
Run Code Online (Sandbox Code Playgroud)__version__ = "$Revision: 63990 $" # $Source$这些行应该包含在模块的docstring之后,在任何其他代码之前,由上面和下面的空行分隔.
您还应确保版本号符合PEP 440(PEP 386,此标准的先前版本)中所述的格式.
Zoo*_*oko 105
我使用单个_version.py文件作为存储版本信息的"one cannonical place":
它提供了一个__version__属性.
它提供标准元数据版本.因此,它将通过pkg_resources解析包元数据的其他工具(EGG-INFO和/或PKG-INFO,PEP 0345)进行检测.
在构建软件包时,它不会导入您的软件包(或其他任何东西),这可能会在某些情况下导致问题.(请参阅下面的评论,了解这可能导致的问题.)
版本号只写下一个地方,因此当版本号更改时只有一个地方可以更改它,并且版本不一致的可能性更小.
以下是它的工作原理:存储版本号的"一个规范位置"是一个.py文件,名为"_version.py",位于Python包中,例如myniftyapp/_version.py.此文件是Python模块,但您的setup.py不会导入它!(这会打败功能3.)而不是你的setup.py知道这个文件的内容非常简单,如:
__version__ = "3.6.5"
Run Code Online (Sandbox Code Playgroud)
所以你的setup.py打开文件并解析它,代码如下:
import re
VERSIONFILE="myniftyapp/_version.py"
verstrline = open(VERSIONFILE, "rt").read()
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
mo = re.search(VSRE, verstrline, re.M)
if mo:
verstr = mo.group(1)
else:
raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
Run Code Online (Sandbox Code Playgroud)
然后你的setup.py将该字符串作为"version"参数的值传递给setup(),从而满足功能2.
为了满足功能1,你可以拥有你的包(在运行时,而不是在设置时!)从myniftyapp/__init__.py这里导入_version文件:
from _version import __version__
Run Code Online (Sandbox Code Playgroud)
这是我多年来一直使用的这种技术的一个例子.
该示例中的代码有点复杂,但我在本评论中写的简化示例应该是一个完整的实现.
以下是导入版本的示例代码.
如果您发现此方法有任何问题,请告诉我们.
sor*_*rin 96
经过十多年编写Python代码和管理各种软件包后,我得出结论,DIY可能不是最好的方法.
我开始使用pbr包来处理我的包中的版本控制.如果您使用git作为您的SCM,这将适合您的工作流程,如魔术,节省您的工作周(您会惊讶于问题的复杂程度).
截至今天,pbr排名第11位最常用的python包,达到这个级别并没有包含任何肮脏的技巧:只有一个:以一种非常简单的方式解决常见的包装问题.
pbr 可以做更多的包维护负担,不仅限于版本控制,但它不会强迫你采用它的所有好处.
因此,为了让您了解它在一次提交中采用pbr的样子,请查看pbr的swiching包装
可能你会发现版本根本没有存储在存储库中.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'
Run Code Online (Sandbox Code Playgroud)
内部yourpackage/__init__.py:
from .version import __version__
Run Code Online (Sandbox Code Playgroud)
内部setup.py:
exec(open('yourpackage/version.py').read())
setup(
...
version=__version__,
...
Run Code Online (Sandbox Code Playgroud)
如果您知道其他方法似乎更好,请告诉我.
Odd*_*ing 29
根据延迟的PEP 396(模块版本号),有一种建议的方法可以做到这一点.它有理由描述了模块的(公认的可选)标准.这是一个片段:
3)当模块(或包)包含版本号时,该
__version__属性应该可以使用该版本.4)对于存在于命名空间包内的模块,模块应该包含该
__version__属性.命名空间包本身不应该包含自己的__version__属性.5)
__version__属性的值应该是一个字符串.
JAB*_*JAB 21
虽然这可能为时已晚,但有一个比上一个答案稍微简单的替代方案:
__version_info__ = ('1', '2', '3')
__version__ = '.'.join(__version_info__)
Run Code Online (Sandbox Code Playgroud)
(使用str().将版本号的自动递增部分转换为字符串相当简单.)
当然,从我所看到的情况来看,人们在使用时倾向于使用类似于前面提到的版本的东西__version_info__,因此将其存储为整数元组; 但是,我没有完全看到这样做的重点,因为我怀疑在某些情况下你会为了除了好奇心或自动增量之外的任何目的在版本号的部分上执行数学运算,例如加法和减法(即便如此,int()并且str()可以相当容易地使用).(另一方面,有可能其他人的代码期望数字元组而不是字符串元组因此失败.)
当然,这是我自己的观点,我很乐意让其他人投入使用数字元组.
正如shezi提醒我的那样,(词汇)数字串的比较不一定与直接数字比较具有相同的结果; 领先的零将需要提供.因此,最后,存储__version_info__(或任何它将被称为)作为整数值的元组将允许更有效的版本比较.
ing*_*ere 12
自从第一次提出这个问题以来,关于统一版本控制和支持约定的大量工作已经完成。《Python 打包用户指南》中现已详细介绍了可口的选项。另外值得注意的是,Python 中的版本号方案相对严格(按照 PEP 440) ,因此如果您的软件包将发布到Cheese Shop,保持理智至关重要。
以下是版本控制选项的简短细分:
setup.py读取( setuptools )中的文件并获取版本。__init__.py以及源代码控制),例如bump2version、changes或zest.releaser。__version__特定模块中的全局变量。setup.py,并使用importlib.metadata在运行时获取它。(警告,有 3.8 之前的版本和 3.8 之后的版本。)__version__insample/__init__.py并导入示例 in setup.py。请注意,(7)可能是最现代的方法(构建元数据独立于代码,由自动化发布)。另请注意,如果安装程序用于软件包发布,则简单的python3 setup.py --version将直接报告版本。
And*_*Lee 10
我在包dir中使用了一个JSON文件.这符合Zooko的要求.
内部pkg_dir/pkg_info.json:
{"version": "0.1.0"}
Run Code Online (Sandbox Code Playgroud)
内部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'],
...
)
Run Code Online (Sandbox Code Playgroud)
内部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']
Run Code Online (Sandbox Code Playgroud)
我还提供其他信息pkg_info.json,如作者.我喜欢使用JSON,因为我可以自动管理元数据.
cmc*_*nty 10
这里的许多解决方案都忽略了git版本标签,这仍然意味着你必须在多个地方跟踪版本(糟糕).我实现了以下目标:
gitrepo中的标记派生所有python版本引用git tag/ push和setup.py upload步骤.从make release命令中,找到git repo中的最后一个标记版本并递增.标签被推回origin.
该Makefile存储的版本在src/_version.py那里将被读取setup.py,并且还包含在释放.不要检查_version.py源代码管理!
setup.py命令从中读取新版本字符串package.__version__.
# 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
Run Code Online (Sandbox Code Playgroud)
该release目标总是递增第三版数字,但可以使用next_minor_ver或next_major_ver递增其他数字.命令依赖于versionbump.py检入repo根目录的脚本
"""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
Run Code Online (Sandbox Code Playgroud)
这将解决如何处理和增加版本号的问题git.
该my_module/_version.py文件已导入my_module/__init__.py.在此处放置您希望与模块一起分发的任何静态安装配置.
from ._version import __version__
__author__ = ''
__email__ = ''
Run Code Online (Sandbox Code Playgroud)
最后一步是从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__'],
...
...
)
Run Code Online (Sandbox Code Playgroud)
当然,要使所有这些工作,你必须在你的仓库中至少有一个版本标签才能开始.
git tag -a v0.0.1
Run Code Online (Sandbox Code Playgroud)
另外值得注意的是,这也是__version__一个半标准.在python中所以__version_info__它是一个元组,在简单的情况下你可以做类似的事情:
__version__ = '1.2.3'
__version_info__ = tuple([ int(num) for num in __version__.split('.')])
Run Code Online (Sandbox Code Playgroud)
...你可以__version__从文件或其他任何东西中获取字符串.
似乎没有一种标准方法可以在python包中嵌入版本字符串.我见过的大多数软件包都使用了解决方案的一些变体,即eitner
将版本嵌入setup.py并setup.py生成一个模块(例如version.py),其中仅包含由您的软件包导入的版本信息,或者
反过来:将版本信息放入包中,然后导入它以设置版本 setup.py
箭头以一种有趣的方式处理它。
现在(从2e5031b 开始)
在arrow/__init__.py:
__version__ = 'x.y.z'
Run Code Online (Sandbox Code Playgroud)
在setup.py:
from arrow import __version__
setup(
name='arrow',
version=__version__,
# [...]
)
Run Code Online (Sandbox Code Playgroud)
前
在arrow/__init__.py:
__version__ = 'x.y.z'
VERSION = __version__
Run Code Online (Sandbox Code Playgroud)
在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__'),
# [...]
)
Run Code Online (Sandbox Code Playgroud)
setuptools和pbr没有管理版本的标准方法,但管理包的标准方法是setuptools.
setuptools我发现总体上管理版本的最佳解决方案是与扩展一起使用pbr。现在这是我管理版本的标准方法。
对于简单的项目来说,将项目设置为完整打包可能有点大材小用,但如果您需要管理版本,那么您可能处于正确的级别来设置所有内容。这样做还可以使您的包可以在PyPi上发布,以便每个人都可以下载它并将其与 Pip 一起使用。
PBR 将大多数元数据从setup.py工具中移出并放入一个setup.cfg文件中,然后将该文件用作大多数元数据(可以包括版本)的源。这允许使用类似的东西将元数据打包到可执行文件中pyinstaller(如果需要的话,您可能需要此 info),并将元数据与其他包管理/设置脚本分开。您可以直接手动更新版本字符串,在构建软件包版本时setup.cfg它将被拉入文件夹中。*.egg-info然后,您的脚本可以使用各种方法从元数据访问该版本(这些过程将在下面的部分中概述)。
当将 Git 用于 VCS/SCM 时,此设置甚至更好,因为它将从 Git 中提取大量元数据,以便您的存储库可以成为某些元数据的主要真实来源,包括版本、作者、更改日志、具体来说,对于版本,它将根据存储库中的 git 标签为当前提交创建版本字符串。
setup.py和文件。setup.cfgsetup.cfg由于 PBR 会直接从您的 git 存储库中提取版本、作者、变更日志和其他信息,因此每当为您的包创建发行版时,可以省略并自动生成一些元数据(使用setup.py)
setuptools将使用以下方式实时提取最新信息setup.py:
python setup.py --version
Run Code Online (Sandbox Code Playgroud)
setup.cfg这将根据最新的提交和存储库中存在的标签,从文件或 git 存储库中提取最新版本。不过,此命令不会更新发行版中的版本。
setup.py当您使用(即例如)创建发行版时py setup.py sdist,所有当前信息将被提取并存储在发行版中。这本质上是运行setup.py --version命令,然后将该版本信息存储到package.egg-info存储分发元数据的一组文件的文件夹中。
关于更新版本元数据的过程的注意事项:
如果您不使用 pbr 从 git 提取版本数据,则只需使用新版本信息直接更新 setup.cfg(很简单,但请确保这是发布过程的标准部分)。
如果您使用 git,并且不需要创建源代码或二进制发行版(使用命令
python setup.py sdist或其中一个python setup.py bdist_xxx命令),将 git 存储库信息更新到元数据文件夹的最简单方法<mypackage>.egg-info就是运行python setup.py install命令。这将运行与从 git 存储库提取元数据相关的所有 PBR 功能并更新本地.egg-info文件夹、为您定义的任何入口点安装脚本可执行文件,以及运行此命令时可以从输出中看到的其他功能。请注意,该
.egg-info文件夹通常不会存储在标准 Python.gitignore文件(例如Gitignore.IO)中的 git 存储库本身中,因为它可以从您的源生成。如果被排除,请确保您有一个标准的“发布流程”来在发布之前在本地更新元数据,并且您上传到 PyPi.org 或以其他方式分发的任何包都必须包含此数据以获得正确的版本。如果您希望 Git 存储库包含此信息,您可以排除特定文件以使其不被忽略(即添加!*.egg-info/PKG_INFO到.gitignore)
您可以在包本身的 Python 脚本中访问当前版本的元数据。例如,对于版本,到目前为止我发现有几种方法可以做到这一点:
## This one is a new built-in as of Python 3.8.0 should become the standard
from importlib.metadata import version
v0 = version("mypackage")
print('v0 {}'.format(v0))
## I don't like this one because the version method is hidden
import pkg_resources # part of setuptools
v1 = pkg_resources.require("mypackage")[0].version
print('v1 {}'.format(v1))
# Probably best for pre v3.8.0 - the output without .version is just a longer string with
# both the package name, a space, and the version string
import pkg_resources # part of setuptools
v2 = pkg_resources.get_distribution('mypackage').version
print('v2 {}'.format(v2))
## This one seems to be slower, and with pyinstaller makes the exe a lot bigger
from pbr.version import VersionInfo
v3 = VersionInfo('mypackage').release_string()
print('v3 {}'.format(v3))
Run Code Online (Sandbox Code Playgroud)
您可以将其中之一直接放入__init__.py包中以提取版本信息,如下所示,类似于其他一些答案:
__all__ = (
'__version__',
'my_package_name'
)
import pkg_resources # part of setuptools
__version__ = pkg_resources.get_distribution("mypackage").version
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
106523 次 |
| 最近记录: |