是否有一种标准的方法将版本字符串与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。
当前回答
不是直接回答你的问题,但你应该考虑将其命名为__version__,而不是version。
这几乎是一个准标准。标准库中的许多模块使用__version__,这也在许多第三方模块中使用,因此它是准标准的。
通常,__version__是一个字符串,但有时它也是一个浮点数或元组。
正如S.Lott所提到的(谢谢!),PEP 8明确表示:
模块级别Dunder名称 模块级别的“dunders”(即名称有两个前导和两个后导 下划线),例如__all__, __author__, __version__等。 应该放在模块文档字符串之后,但在任何导入之前 除了__future__导入之外的语句。
您还应该确保版本号符合PEP 440 (PEP 386是此标准的以前版本)中描述的格式。
其他回答
无论如何,如果你使用NumPy distutils, NumPy .distutils.misc_util。Configuration有一个make_svn_version_py()方法,它将版本号嵌入到包中。变量version中的__svn_version__。
同样值得注意的是,__version__是一个半std。在python中,__version_info__也是一个元组,在简单的情况下,你可以这样做:
__version__ = '1.2.3'
__version_info__ = tuple([ int(num) for num in __version__.split('.')])
...你可以从文件或其他地方获取__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,因为我可以自动管理元数据。
我更喜欢从安装环境中读取包版本。 这是我的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',
},
)
我使用一个单独的_version.py文件作为“曾经正确的位置”来存储版本信息:
It provides a __version__ attribute. It provides the standard metadata version. Therefore it will be detected by pkg_resources or other tools that parse the package metadata (EGG-INFO and/or PKG-INFO, PEP 0345). It doesn't import your package (or anything else) when building your package, which can cause problems in some situations. (See the comments below about what problems this can cause.) There is only one place that the version number is written down, so there is only one place to change it when the version number changes, and there is less chance of inconsistent versions.
它是这样工作的:存储版本号的“一个规范的地方”是一个.py文件,名为“_version.py”,它在你的Python包中,例如在myniftyapp/_version.py中。这个文件是一个Python模块,但是你的setup.py没有导入它!(这将击败功能3。)相反,你的setup.py知道这个文件的内容非常简单,就像:
__version__ = "3.6.5"
所以你的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,))
然后你的setup.py将这个字符串作为"version"参数的值传递给setup(),这样就满足了特性2。
为了满足特性1,你可以让你的包(在运行时,而不是在设置时!)像这样从myniftyapp/__init__.py导入_version文件:
from _version import __version__
这是我多年来一直在使用的一个技巧的例子。
这个例子中的代码有点复杂,但是我写在这个注释中的简化的例子应该是一个完整的实现。
下面是导入版本的示例代码。
如果你发现这种方法有任何问题,请告诉我。