Python能做大项目(6)Poetry -- 项目管理的诗和远方之一

[Poetry] 是一个依赖管理和打包工具。Poetry 的作者解释开发 Poetry 的初衷时说:

在这里插入图片描述

通过前面的案例,我们已经提出了一些问题。但不止于此。

当您将依赖加入到 requirements.txt 时,没有人帮你确定它是否与既存的依赖能够和平共处,这个过程要比我们想象的复杂许多,不仅仅是直接依赖,还需要考虑彼此的传递依赖是否也能彼此兼容;所以一般的做法是,先将它们加进来,完成开发和测试,在打包之前,运行pip freeze > requirements.txt来锁定依赖库的版本。但我们也在前面的案例中提到,这种方法可能会将不必要的开发依赖打入到发行版中;此外,它也会过度锁定版本,从而使得一些活跃的第三方库失去自动更新热修复和安全更新的机会。

项目的版本管理也是一个问题。在老旧的 Python 项目中,一般我们使用 bumpversion 来管理版本,它需要使用三个文件。在我的日常使用时,它常常会出现各种问题,最常见的是单双引号导致把__version__ = 0.1当成一个版本号,而不是0.1。这样打出来的包名也会奇怪地多一个无意义的 version 字样。单双引号则是因为你的 format 工具对字符串常量应该使用什么样的引号规则有自己的意见。

项目进行打包和发布需要准备太多的文件,正如 Poetry 的开发者所说,要确保这些文件的内容完全正确,对一个有经验的开发者来说,也不是轻而易举的事。

Poetry 解决了所有这些问题(除了案例中的第一个,该问题要通过 tox 和 CI 来解决)。它提供了版本管理、依赖解析、构建和发布的一站式服务,并将所有的配置,集中到一个文件中,即 pyproject.toml。此外,Poetry 还提供了一个简单的工程创建向导。不过这个向导的功能仍然过于简单,我们的推荐则是使用上一章介绍的 python project wizard。

在这里插入图片描述

现在,让我们看一眼 sample 项目中的 pyproject.toml 文件:

[tool]
[tool.poetry]
name = "sample"
version = "0.1.0"
homepage = "https://github.com/zillionare/sample"
description = "Skeleton project created by Python Project Wizard (ppw)."
authors = ["aaron yang <aaron_yang@jieyu.ai>"]
readme = "README.md"
license =  "MIT"
classifiers=['Development Status :: 2 - Pre-Alpha','Intended Audience :: Developers','License :: OSI Approved :: MIT License','Natural Language :: English','Programming Language :: Python :: 3','Programming Language :: Python :: 3.7','Programming Language :: Python :: 3.8','Programming Language :: Python :: 3.9','Programming Language :: Python :: 3.10',
]
packages = [{ include = "sample" },{ include = "tests", format = "sdist" },
][tool.poetry.dependencies]
python = ">=3.7.1,<4.0"
fire = "0.4.0"black  = { version = "^22.3.0", optional = true}
isort  = { version = "5.10.1", optional = true}
flake8  = { version = "4.0.1", optional = true}
flake8-docstrings = { version = "^1.6.0", optional = true }
pytest  = { version = "^7.0.1", optional = true}
pytest-cov  = { version = "^3.0.0", optional = true}
tox  = { version = "^3.24.5", optional = true}
virtualenv  = { version = "^20.13.1", optional = true}
pip  = { version = "^22.0.3", optional = true}
mkdocs  = { version = "^1.2.3", optional = true}
mkdocs-include-markdown-plugin  = { version = "^3.2.3", optional = true}
mkdocs-material  = { version = "^8.1.11", optional = true}
mkdocstrings  = { version = "^0.18.0", optional = true}
mkdocs-material-extensions  = { version = "^1.0.3", optional = true}
twine  = { version = "^3.8.0", optional = true}
mkdocs-autorefs = {version = "^0.3.1", optional = true}
pre-commit = {version = "^2.17.0", optional = true}
toml = {version = "^0.10.2", optional = true}
livereload = {version = "^2.6.3", optional = true}
pyreadline = {version = "^2.1", optional = true}
mike = { version="^1.1.2", optional=true}[tool.poetry.extras]
test = ["pytest","black","isort","flake8","flake8-docstrings","pytest-cov"]dev = ["tox", "pre-commit", "virtualenv", "pip", "twine", "toml"]doc = ["mkdocs","mkdocs-include-markdown-plugin","mkdocs-material","mkdocstrings","mkdocs-material-extension","mkdocs-autorefs","mike"][tool.poetry.scripts]
sample = 'sample.cli:main'[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"[tool.black]
line-length = 88
include = '\.pyi?$'
exclude = '''
/(\.eggs| \.git| \.hg| \.mypy_cache| \.tox| \.venv| _build| buck-out| build| dist
)/
'''
[tool.isort]
profile = "black"

我们简单地解读一下这个文件:
在 [tool.poetry] 那一节,定义了包的名字(这里是 sample)、版本号(这里是 0.1.0)和其它的一些字段,比如 classifiers,这是打包和发布时需要的。如果您熟悉 python setup tools,那么对这些字段将不会陌生。packages 字段指明了打包时需要包含的文件。在示例中,我们要求在以.whl 格式发布的包中,将 sample 目录下的所有文件打包发布;而以 sdist 格式(即.tar.gz) 发布的包中,还要包含 tests 目录下的文件。

接下来是 [tool.poetry.dependencies] 一节,这是我们声明项目依赖的地方。首先是项目要求的 python 版本声明。这里我们要求必须在 3.7.1 以上,4.0 以下的 python 环境中运行。因此,python 3.7.1,3.8, 3.9, 3.10 都是恰当的 python 版本,但 4.0 则不允许。

接下来就是工程中需要用到的其它第三方依赖,有运行时的(即当最终用户使用我们的程序时,必须安装的那些第三方依赖),也有开发时的(即只在开发和测试过程中使用到的,比如文档工具类 mkdocs,测试类 tox, pytest 等)。

我们对运行时和开发时需要的依赖进行了分组。对开发时需要的依赖,我们分成 dev, test 和 doc 三组,通过 [tool.poetry.extras] 中进行分组声明。对于归入到 dev, test 和 doc 分组中的依赖,我们在 [tool.poetry.dependencies] 中,将其声明为 optional 的,这样在安装最终分发包时,这些声明为 optional 的第三方依赖将不会安装到用户环境中。

再接下来,[tool.poetry.scripts] 声明了一个 console script 入口。Console script 是一种特殊的 Python 脚本,它使得您可以象调用普通的 shell 命令一样来调用这个脚本。

[tool.poetry.scripts]
sample = 'sample.cli:main'

在这里插入图片描述

当 sample 包被安装后,就往安装环境里注入了一个名为sample的shell 命令。它可以接受各种参数,最终将交给 sample\cli.py 中的 main 函数来执行。

接下来就是关于如何构建的相关指示,在 [build-system] 中。如果你的程序中只包含纯粹的 Python 代码,那么这部分可不做任何修改。如果你的程序包含了一些原生的代码(比如 c 的),那么就需要自己定义构建脚本。

在示例代码中,还有 [tool.black] 和 [tool.isort] 两个小节,分别是 black(代码格式化工具)和 isort(将导入进行排序的工具)的配置文件。它们是对 pyproject.toml 的扩展,并不是 poetry 所要求的。

版本管理

poetry 为我们的 package 提供了基于语义 (semantic version) 的版本管理功能。它通过poetry version这个命令,让我们查看 package 的版本,并且实现版本号的升级。

假设您已经使用 [python project wizard] 生成了一个工程框架,那么应该可以在根目录下找到 pyproject.toml 文件,其中有一项:

version = 0.1

如果您现在运行poetry version这个命令,就会显示0.1这个版本号。

Poetry 使用基于语义的版本 (semantic version) 表示法。

在 Poetry 中,当我们需要修改版本号时,并不是直接指定新的版本号,而是通过poetry version semver来修改版本。semver可以是patch, minor, major, prepatch, preminor, premajorprerelease中的一个。这些关键字定义在规范 PEP 440 中。

semver与您当前的版本号相结合,通过运算,就得出了新的版本号:

rulebeforeafter
major1.3.02.0.0
minor2.1.42.2.0
patch4.1.14.1.2
premajor1.0.22.0.0-alpha.0
preminor1.0.21.1.0-alpha.0
prepatch1.0.21.0.3-alpha.0
prerelease1.0.21.0.3-alpha.0
prerelease1.0.3-alpha.01.0.3-alpha.1
prerelease1.0.3-beta.01.0.3-beta.1

可以看出,poetry 对版本号的管理是完全符合 semantic version 的要求的。当你完成了一个小的修订(比如修复了一个 bug,或者增强了性能,或者修复了安全漏洞),此时只应该递增 package 的修订号,即 x.y.z 中的’z’,这时我们就应该使用命令:

$ poetry version patch

如果之前的版本是 0.1.0,那么运行上述命令后,版本号将变更为 0.1.1。
如果我们的 package 新增加了一些功能,而之前提供的功能(API)都还能不加修改,继续使用,那么我们应该递增次版本号,即 x.y.z 中的’y’。这时我们应该使用命令:

$ poetry version minor

如果之前的版本是 0.1.1,那么运行上述命令后,版本号将变更为 0.2.0

如果我们的 package 进行了大幅的修改,并且之前提供的功能(API)的签名已经变掉,从而使得调用者必须修改他们的程序才能继续使用这些 API,又或者新的版本不再能兼容老版本的数据格式,用户必须对数据进行额外的迁移,那么,我们就认为这是一次破坏性的更新,必须升级主版本号:

$ poetry version major

如果之前的版本号是 0.3.1, 那么运行上述命令之后,版本号将变更为 1.0.0;如果之前的版本号是 1.2.1,那么运行上述命令之后,版本号将变更为 2.0.0。

除此之外,poetry 还提供了预发布版本号的支持。比如,上一个发布的版本是 0.1.0,那么我们在正式发布 0.1.1 这个修订之前,可以使用 0.1.1.a0 这个版本号:

$ poetry version prerelease
Bumping version from 0.1.0 to 0.1.1a0

如果需要再出一个 alpha 版本,则可以再次运行上述命令:

$ poetry version prerelease
Bumping version from 0.1.1a0 to 0.1.1a1

如果 alpha 版本已经完成,可以正式发布,运行下面的命令:

$ poetry version patch
Bumping version from 0.1.1a1 to 0.1.1

poetry 暂时还没有提供从 alpha 转到 beta 版本系列的命令。如果有此需要,您需要手工编辑 pyproject.toml 文件。

除了 poetry version prerelease 之外,我们还注意到上面列出的 premajor, preminor 和 prepatch 选项。它们的作用也是将版本号修改为 alpha 版本系列,但无论你运行多少次,它们并不会象 prerelease 选项一样,递增 alpha 版本号。所以在实际的 alpha 版本管理中,似乎只使用poetry version prerelease就可以了。


本文来源于《Python能做大项目》(暂定名),将由机械工业出版社出版。全书已经在大富翁量化官网上首发,欢迎提前阅读。


【本系列其它文章】

Python能做大项目(1) - 为什么要学Python之一
Python能做大项目(2) - 开发环境构建
Python能做大项目(3) - 依赖地狱与Conda虚拟环境
Python能做大项目(4) - 项目布局与生成向导
Python能做大项目(5) - 基于语义的版本管理
Python能做大项目(6) - Poetry: 项目管理的诗和远方之一

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/299936.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言中关于if else的理解

if else我们可以理解为 if(条件1) //如果条件1成立 语句1&#xff1b; //执行语句1 else //如果条件1不成立 语句2; //执行语句2 这是一个经典的if els…

linux 系统重启 Redis 服务

先 打开服务器 执行 sudo systemctl stop redis暂停Redis服务 然后 执行 sudo systemctl start redis启动 redis 服务 然后可以执行 sudo systemctl status redis查看 redis 状态

电商数据分析-01-电商数据分析指标

电商数据指标 电商数据分析涉及多个指标&#xff0c;这些指标可以帮助企业了解其业务表现、用户行为和市场趋势。以下是一些常见的电商数据分析指标&#xff1a; 销售指标&#xff1a; 总销售额&#xff08;GMV&#xff09;&#xff1a; 衡量特定时期内所有销售交易的总值。 平…

关于Sneaky DogeRAT特洛伊木马病毒网络攻击的动态情报

一、基本内容 作为复杂恶意软件活动的一部分&#xff0c;一种名为DogeRAT的新开源远程访问特洛伊木马&#xff08;RAT&#xff09;主要针对位于印度的安卓用户发动了网络安全攻击。该恶意软件通过分享Opera Mini、OpenAI ChatGOT以及YouTube、Netfilx和Instagram的高级版本等合…

传感器原理与应用复习—测量概述与测量误差

文章目录 测量概论测量误差下一篇 测量概论 通常的测量结果包括比值和测量单位 测量结果的完整描述应包括估计值&#xff0c;测量单位及测量的不确定度&#xff08;误差&#xff09; 测量分类&#xff1a; 根据测得的值是否直接使用 直接测量&#xff1a;不需要经过任何运算&…

Spring(3)Spring从零到入门 - Spring整合技术及AOP事务管理

Spring&#xff08;3&#xff09;Spring从零到入门 - Spring整合技术及AOP事务管理 文章目录 Spring&#xff08;3&#xff09;Spring从零到入门 - Spring整合技术及AOP事务管理4 Spring整合技术示例4.1 Spring整合Mybatis4.1.1 Mybatis开发回顾4.1.2 整合Spring分析4.1.3 Spri…

Object.hashCode() 详解

在Java编程中&#xff0c;hashCode方法是一个常见而重要的概念。它通常用于哈希表、集合以及一些需要高效检索数据的数据结构中。然而&#xff0c;对于许多开发者来说&#xff0c;hashCode方法可能是一个容易被忽略或者被简单实现的部分。在本文中&#xff0c;我们将深入探讨Ja…

ElasticSearch 使用映射定义索引结构

动态映射 dynamic 可选值解释true默认值&#xff0c;启用动态映射&#xff0c;新增的字段会添加到映射中runtime查询时动态添加到映射中false禁用动态映射&#xff0c;忽略未知字段strict发现未知字段&#xff0c;抛出异常 显示映射 创建映射 PUT user {"mappings&qu…

VMware安装linux系统一

1、创建虚拟机 1.1、创建新的虚拟机 1.2、进入安装向导 1.3、安装操作系统&#xff0c;选择稍后安装操作系统 1.4、选择Linux,版本选择CentOS64位 1.5、设置虚拟机名称和安装位置 1.6、设置磁盘大小 1.7、创建虚拟机 1.8、完成安装 2、配置虚拟机 2.1、选择编辑虚拟机 2.2、修…

假期返乡的消费者,县城外卖消费上涨,如何实现外卖自由?

假期即将来临&#xff0c;年轻的消费者回到小县城过节&#xff0c;也开始将他们的"外卖买一切"的消费习惯带回了家乡。线上"赶集"的新型消费模式让消费者在家门口一站式购齐年货&#xff0c;既方便又实惠。因此&#xff0c;小县城的外卖订单量也大幅增长。…

Jenkins的特殊操作定时自动执行任务以及测试报告调优

java -Dhudson.model.DirectoryBrowserSupport.CSP -jar Jenkins.war 测试报告 不美丽 执行上面的代码 重启jenkins 就好了

浅谈故障注入目的与优势

故障注入是一种有意识地向系统或软件中引入错误、故障或异常的测试技术。这种方法旨在评估系统在异常情况下的表现&#xff0c;并帮助发现潜在的问题&#xff0c;以便在生产环境中减少故障的风险。本文将介绍故障注入目的与优势有哪些! 故障注入的主要目的是在安全的环境下评估…