跳转到主要内容

Poetry插件,用于从__version__变量或Git标签中动态提取包版本。

项目描述

🚨 警告:已弃用 🚨

此项目已弃用。您不应使用它。如果您将其用于现有库,则应迁移到其他项目。

构建应用程序

如果您正在构建应用程序(而不是库包),并且希望有一个包含您使用的确切依赖项的锁定文件以实现精确复制,我建议您尝试 uv

构建库

如果您正在为他人构建库,您也可以使用 uv 来管理项目,然后您可以使用 PDM 来处理库构建部分,它具有 内置的动态版本支持

如果您想从其他地方提取版本或以任何方式修改元数据,PDM 也提供了您可以使用的构建 钩子

迁移

如果您已经有一个使用 Poetry 的库,您可以使用 import 命令 迁移到 PDM。

PDM、uv 等使用标准在 pyproject.toml 中声明项目元数据和依赖项,因此,如果您使用该 PDM import 命令迁移到标准格式,您将能够使用任何兼容的工具,例如 uv

Poetry 代替方案

如果您出于某种原因需要继续使用 Poetry,可以考虑 poetry-dynamic-versioning。✨


以下信息仅保留为历史原因。🤓 🦕

Poetry 版本插件

Test Publish Coverage Package version

一个用于动态提取软件包 版本Poetry 插件。

它可以读取一个包含以下内容的文件 __init__.py 中的版本:

# __init__.py

__version__ = "0.1.0"

或者,它可以从一个 git 标签 中读取版本,该标签通过 GitHub 发布或设置:

$ git tag 0.1.0

🚨 请注意,这处于 alpha 阶段。请阅读下面的警告。

何时使用

这主要适用于您正在构建一个用于他人使用的包库,并且您想在不同于 pyproject.toml 的地方设置版本,但您仍然想保持一个 单一事实来源

在其他用例中,如使用 Poetry 管理本地应用环境,这可能没有帮助。

替代方案

如果您正在构建一个包库并想要此功能,但实际上不需要 Poetry 的其他任何东西,您可能最好使用 HatchPDM 或其他带有此功能内置而不需要插件的替代方案。

如何使用

确保您有 Poetry 版本 1.2.0 或更高版本。如果您还没有安装它,请阅读以下说明。

安装 Poetry 版本插件

将此插件安装到您的 Poetry 中

$ poetry self add poetry-version-plugin

--> 100%

在初始化文件中设置版本

在您的文件 __init__.py 中设置您的包版本,例如

from .main import do_awesome_stuff, AwesomeClass

__version__ = "0.2.3"

然后编辑您的 pyproject.toml,包含以下部分:

[tool.poetry-version-plugin]
source = "init"

接下来,构建您的项目。它将显示如下输出:

$ poetry build
Using __init__.py file at my_awesome_package/__init__.py for dynamic version
Setting package dynamic version to __version__ variable from __init__.py: 0.1.9
Building my-awesome-package (0.1.9)
  - Building sdist
  - Built my-awesome-package-0.1.9.tar.gz
  - Building wheel
  - Built my-awesome-package-0.1.9-py3-none-any.whl

在 Git 标签中设置版本

或者,要从一个 Git 标签中提取版本以使用,请添加以下部分:

[tool.poetry-version-plugin]
source = "git-tag"

然后创建一个 git 标签,例如

$ git tag 0.1.3

在这种情况下,当构建您的项目时,它将显示如下输出:

$ poetry build
Git tag found, setting dynamic version to: 0.1.3
Building my-awesome-package (0.1.3)
  - Building sdist
  - Built my-awesome-package-0.1.3.tar.gz
  - Building wheel
  - Built my-awesome-package-0.1.3-py3-none-any.whl

pyproject.toml 中的版本

目前(2021-05-24)Poetry 要求在 pyproject.toml 中有一个 version 配置,即使您使用此插件也是如此。

使用此插件时,该 version 配置将不会被使用,但 Poetry 仍然要求它存在于 pyproject.toml 中。

为了更明显地表明您没有使用该 version,您可以将其设置为 0

[tool.poetry]
name = "my-awesome-package"
version = "0"

这样,您将更容易注意到插件是否未安装,因为它将显示您正在构建一个版本为 0 的包,而不是设置的动态版本。

一个示例 pyproject.toml

一个简短的、最小化的示例 pyproject.toml 可能如下所示:

[tool.poetry]
name = "my-awesome-package"
version = "0"
description = ""
authors = ["Rick Sanchez <rick@rick-citadel.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.7"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.poetry-version-plugin]
source = "init"

为什么

默认情况下,Poetry 期望您在 pyproject.toml 中设置您的包版本。这在大多数情况下是可行的。

但想象一下,您希望将包的版本暴露在 __version__ 变量中,以便您的用户可以执行类似以下操作:

import my_awesome_package
print(my_awesome_package.__version__)

您可以手动编写 __version__ 变量并自己处理与 pyproject.toml 之间的同步,这非常 容易出错

当前 官方的无需重复值的方式 是使用 importlib.metadata

但是该模块仅适用于Python 3.8及以上版本。因此,对于Python 3.7,您必须将回端口作为您包的依赖项安装。

[tool.poetry.dependencies]
importlib-metadata = {version = "^1.0", python = "<3.8"}

然而,每当它们发布回端口的每个新版本(目前为4.0.1)时,您必须更新它(或不更新)。您的用户将不得不手动处理与依赖importlib-metadata的任何其他包之间的冲突,这可能有很多,因为许多包可能正在执行相同的技巧(我处理过这种情况)。

另一个选项是在您的pyproject.toml中不锁定任何版本的importlib-metadata,并寄希望于最佳情况。

然后,您的__init__.py必须包含使用它的代码,例如

# I don't want this extra complexity 😔
# And it doesn't work in Docker 🐋
try:
    import importlib.metadata as importlib_metadata
except ModuleNotFoundError:
    import importlib_metadata

__version__ = importlib_metadata.version(__name__)

但是,这段代码是您代码中的额外复杂性和逻辑,在每个您的包中。

🚨 此外,这仅当您的包安装在Python环境中时才有效。例如,如果您只是将代码放入一个容器中(这对于Web应用和分布式系统来说是常见的),它将不起作用。

此插件如何解决这个问题

使用此插件,您的包不依赖于importlib-metadata,因此您的用户不需要处理冲突或额外的依赖项。

相反,需要安装此插件的是您的构建系统(Poetry)。

这避免了您这一侧的额外代码复杂性、用户的依赖项冲突,并支持其他用例,如直接在容器内复制的代码。

从Git标签获取版本

此外,此插件还可以从Git标签中提取版本。

因此,您可以在Git标签(例如,GitHub发布)中创建每个版本,而不是将其写入代码。

然后,在持续集成(例如GitHub Actions)上构建包。然后此插件将从该Git标签获取包的版本。

安装Poetry 1.2.0

为此插件能够工作,您需要Poetry版本1.2.0或更高。

最近发布了Poetry 1.2.0.

您很可能已经安装了Poetry 1.1.x

第一步是卸载它

$ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -O
--> 100%

$ python get-poetry.py --uninstall
--> 100%

然后使用新的安装程序安装新的Poetry

$ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -O
--> 100%

$ python install-poetry.py --preview
--> 100%

🔍 注意,新的安装程序文件名为install-poetry.py,而不是get-poetry.py。注意,目前,您需要设置--preview来安装alpha版本1.2.0

您可以使用以下方式来检查它是否已成功工作

$ poetry --version
Poetry (version 1.2.0)

在init文件中支持版本

当在__init__.py中使用__version__变量时,您可以在该文件中包含更多逻辑,导入模块,并在该变量的声明上方和下方执行更多操作。

但是,该值必须是字面字符串,例如

___version___ = "0.2.0"

...而不是调用一个函数或类似的东西。

并且该变量必须是顶级变量,因此它不能位于一个if语句或类似的语句内部。

所有这些都很好,并且在您的__init__.py中得到支持

# __init__.py

# This is all valid 👍✅

from .main import do_awesome_stuff, AwesomeClass

awesome = AwesomeClass()

# Some comment explaining why this is commented out
# __version__ = "1.0.0"

__version__ = "0.2.3"

if __name__ == "__main__":
    awesome.run()

以下示例都是有效且受支持的,它包括

  • 导入
  • 其他对象和变量
  • 注释
  • 注释中的相同字符串__version__
  • 周围的if块

但不支持这一点

# 🚨 Not supported

if 2 == 2:
    __version__ = "0.1.0

也不支持这一点

# 🚨 Not supported

def get_version():
    return "0.2.0"

__version__ = get_version()

插件的工作原理

Poetry在构建包时运行插件,并在创建“包分发版”(例如,wheel)之前设置版本。

版本变量的工作方式

如果您在pyproject.toml中的packages配置中声明了一个包(一个单独的包),则插件将使用该包的__init__.py来查找__version__变量。

如果您没有packages配置,则插件将假定您有一个名为项目的单个包,但以模块版本(将-替换为_)。因此,如果您的包是my-awesome-project,则插件将使用位于my_awesome_project/__init__.py的文件来查找__version__变量。

此文件结构是在使用poetry new命令创建新项目时的默认结构,因此应该按预期工作。✨

插件内部的工作方式是通过解析__init__.py文件。使用Python的ast标准模块读取Python的“抽象语法树”并提取字符串的文本值。因此,它不会执行__init__.py中的代码,只将其作为Python代码读取。

插件不会尝试导入和执行该__init__.py文件,因为这可能需要额外的计算、外部依赖等。它也不会尝试使用正则表达式提取__version__,因为如果代码中其他地方(例如注释或字符串内部)存在另一个__version__,那么这很容易出错。

警告

🚨 请注意,这处于alpha阶段。支持插件的Poetry 1.2.0a1版本于2021年5月21日发布。我于3天后,即2021年5月24日开始编写此插件。

在Poetry或此插件中,某些东西可能会出错。因此,请在完全采用它用于关键系统之前,仔细尝试和测试它。

其工作方式可能会更改,具体配置也可能更改。

此外,如果您觉得以下部分不太直观

[tool.poetry-version-plugin]
source = "init"

并且

[tool.poetry-version-plugin]
source = "git-tag"

请告诉我哪种替代配置对您来说更有意义且更直观。

👍 好消息是,假设您正在构建要上传到PyPI以供用户下载和使用的软件包,如果出现故障,最坏的情况是您将无法构建新版本,直到问题得到修复或更改。但是,您的用户不应受到任何影响。

发行说明

最新更改

0.2.1

🚨 警告:已弃用 🚨

此项目已弃用。您不应使用它。如果您将其用于现有库,则应迁移到其他项目。

您可以在README中了解更多信息:[https://github.com/tiangolo/poetry-version-plugin](https://github.com/tiangolo/poetry-version-plugin)

文档

  • 📝 更新README,更新安装命令,推荐Hatch和PDM。由@tiangolo发起的PR #31
  • 📝 添加关于poetry-dynamic-versioning的提及。由@tiangolo发起的PR #63
  • 📝 废弃poetry-version-plugin,推荐uv,PDM。由@tiangolo发起的PR #62

内部

  • ⬆ 将覆盖率要求从^5.5更新到^7.2。由@dependabot[bot]发起的PR #42
  • ⬆ 将codecov/codecov-action从1提升到4。由@dependabot[bot]发起的PR #53
  • ⬆ 将tiangolo/issue-manager从0.5.0提升到0.5.1。由@dependabot[bot]发起的PR #64
  • ⬆ 将actions/cache从1提升到4。由@dependabot[bot]发起的PR #51
  • ⬆ 将actions/setup-python从1提升到5。由@dependabot[bot]发起的PR #47
  • ⬆ 将actions/checkout从2提升到4。由@dependabot[bot]发起的PR #41
  • 👷 更新issue-manager.yml。由@tiangolo发起的PR #61
  • 👷 更新latest-changes GitHub Action。由@tiangolo发起的PR #60
  • 👷 更新 issue-manager.yml 的 GitHub Action 权限。PR #59@tiangolo 提出。
  • 🔧 添加讨论和问题的 GitHub 模板,以及安全策略。PR #55@alejsdev 提出。
  • 👷 添加 dependabot。PR #37@tiangolo 提出。
  • 👷 升级 latest-changes GitHub Action。PR #35@tiangolo 提出。
  • 👷 更新 latest-changes 的 token。PR #36@tiangolo 提出。

0.2.0

  • ✨ 支持 Poetry 1.2.0 及以上版本(包括 1.5.1),弃用 Python 3.6 的支持。PR #28@mbeacom 提出。
  • ⬆️ 弃用 Python 3.6 并添加最新版本的 CI。PR #32@tiangolo 提出。
  • ✏️ 修复 README.md 中的错别字和措辞。PR #8@Gl0deanR 提出。

0.1.3

  • ✨ 改进日志,以插件名称为前缀。PR #6@tiangolo 提出。
  • 🔧 更新 pyproject 元数据。PR #5@tiangolo 提出。
  • ✅ 修复覆盖率。PR #4@tiangolo 提出。
  • 📝 改进文档。PR #3@tiangolo 提出。
  • 🐛 修复 CI 的测试。PR #1@tiangolo 提出。
  • 👷 修复 Latest Changes action,设置分支为 main。PR #2@tiangolo 提出。

许可证

本项目受 MIT 许可协议约束。

项目详情


下载文件

下载适合您平台文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源代码分发

poetry_version_plugin-0.2.1.tar.gz (8.7 kB 查看哈希)

上传时间 源代码

构建分发

poetry_version_plugin-0.2.1-py3-none-any.whl (9.6 kB 查看哈希)

上传时间 Python 3

支持

AWSAWS云计算和安全赞助商DatadogDatadog监控FastlyFastlyCDNGoogleGoogle下载分析MicrosoftMicrosoftPSF赞助商PingdomPingdom监控SentrySentry错误记录StatusPageStatusPage状态页面