如何使用Poetry(1.2+)管理Python虚拟环境
前记
一个项目最重要的就是跑起来, 大家基本会同时在本地开发多个项目, 而每个项目用到的环境都是不一样的, 如果这些项目都共用一份依赖那么会导致多个项目的依赖发生冲突以及导致线上服务不稳定,所以就需要用到虚拟环境隔离。在Python
中提供了名为venv
的虚拟环境管理包用于做多个项目的环境隔离,它提供了很多基础的功能,但是还有很多功能都需要开发者手动操作非常不方便,这时候就可以用到Poetry
啦。
本文是保障Python项目质量的工具文章中项目环境管理-Poetry
的拓展版,由于Poetry
在1.2后发生了一些大变化,所以本文的内容不保证能支持Poetry
1.2以下的版本。
1.最初的开始
在未依赖任何外部工具时,通常都会使用自带的工具来初始化项目的环境,如下:
1 |
|
这几个命令中,由venv
完成初始化和使用虚拟环境,再由pip
命令来安装包含测试环境的依赖。
这些工具都能正常的使用,但是却有几个弊端:
- 直接使用
python3
命令,无法确定准确的Python
的版本,导致本地的Python
版本与其他人或者服务器的版本不同步。 - 每次都要显式的进入和切换虚拟换(
Pycharm
会默认读取到虚拟环境)。 - 通过
pip
来管理依赖,无法完成依赖管理,也无法自动的对依赖进行分组,如区分测试依赖和正式依赖等。
此外对于打包,推送包之类的功能还需要开发者去手动编辑文件再通过繁杂的命令去处理,这是非常麻烦的,而Poetry
对很多重复且需要开发者手动操作都步骤都统一起来,提供一些命令方便开发者去操作。
Poetry
的安装非常简单,一条命令就可以搞定了,不同系统的安装教程官方已经说得很详细,具体见官方安装文档
2.如何使用Poetry初始化项目环境
如果这是第一个项目,那么可以使用poetry new {项目名}
的命令来创建项目,如下:
1 |
|
这时Poetry
会在当前目录创建一个demo
目录,demo
目录里面的结构如下:
1 |
|
可以看到Poetry
会帮忙创建一个最小项目的结构,其中demo
是我们本次要开发的目录,README.md
是一个项目描述文档,但它是空的,等着我们去填写,tests
则是一个测试用例的目录,而pyproject.toml
是Python
项目相关的一些配置,poetry
会预写一些项目的最小信息,如下:
1 |
|
其中作者信息是通过git config
里面的配置获取的。
如果是在已有项目下使用Poetry
则可以通过poetry init
命令,这样Poetry
就会通过一个交互式命令行来协助开发者创建项目信息和虚拟环境,不过在创建之前要先确保系统上拥有自己想要的Python
版本,Poetry
是不会负责Python
版本的管理的,需要开发者通过手动处理,pyenv
,conda
等命令来完成这一步操作,具体的poetry init
操作如动图:
可以看到如果没有填写值得话,Poetry
会默认为你填写一些值,我在某些选项中填入了一些自己的值,最后pyproject.toml
会生成如下内容:
1 |
|
至此,项目初始化完毕,可以开始编写我们的项目了,但是当用PyCharm
打开项目的时候会发现有如图的提醒:
这个提醒是PyCharm
找不到Poetry
的可执行文件,需要通过我们指定Poetry
的路径才可以执行,这时候可以通过命令:
1 |
|
来获取Poetry
的可执行路径并填写到弹窗里面,之后PyCharm
就会调用Poetry
进行虚拟环境初始化,并在当前路径创建.venv
文件夹,通过poetry env info
获取当前项目的虚拟环境:
1 |
|
- 1.如果想在已有的项目下使用
Poetry
则需要先删除当前的虚拟环境,并通过命令poetry env use 3.9.10
- 2.如果创建的虚拟环境版本不是自己想要的,且是通过
pyenv
管理Python
版本,那么可以通过https://python-poetry.org/blog/announcing-poetry-1.2.0/#detection-of-the-currently-active-python-experimental了解如何解决- 3.如果第二点仍然无法解决问题,可以采用如下命令显示的指导
Poetry
使用到正确的Python
版本:
1
2
pyenv local 3.9.10
poetry env use $(pyenv which python)
3.编写与运行项目
虚拟环境初始化完成后就可以开始编写项目了,这个demo
项目很简单,就是获取一个网站当前的状态,需要用到一个名为httpx
的包,这时可以通过命令:
1 |
|
来安装这个包,当命令执行完毕后,可以发现pyproject.toml
文件新增了一行关于httpx
包的版本描述:
1 |
|
这段描述意味着httpx
的版本会锁定在0.23.1
这个版本中。
安装好依赖后,在demo/__init__.py
编写如下代码:
1 |
|
这段代码非常简单,就是请求https://so1n.me
并打印对应的HTTP状态码,接着可以在终端通过命令直接运行,不用再通激活虚拟环境,运行结果如下:
1 |
|
不过这段命令比较长,经常这样输入会比较麻烦,这时可以采用Poetry
的脚本功能,只需要向pyproject.toml
文件追加如下内容:
1 |
|
这段内容中的demo = 'demo.__init__:main'
以等号分成两边,左边的demo
是脚本key,这意味着在tool.poetry.scripts
中不能出现相同的Key,而等号右边的demo.__init__:main
则代表要执行demo
目录下的__init__.py
的main
函数。
接下来可以通过poetry run {脚本key}
语法来执行我们想要跑的代码,执行效果如下:
1 |
|
除此之外,还可以通过poetry install
的方式来让Poetry
创建我们的demo
脚本:
1 |
|
可以看到Poetry
在/home/so1n/demo/.venv/bin/demo
路径下创建了一个脚本文件,如果这时候如果通过poetry shell
进入带有当前虚拟环境的交互shell
,则可以通过demo
直接执行我们的代码,如下:
1 |
|
4.运行测试用例
项目编写完成后需要确保我们的代码符合规范以及需要补充对应的测试用例,这是一个良好的习惯,在Python
生态中,常用的测试框架是pytest
,常用的检查代码规范则是通过pre-commit
去执行的。
可以通过保障Python项目质量的工具了解有什么提升代码质量的工具以及如何使用
pre-commit
。
在poetry
可以通过如下方式安装pytest
, pytest-asyncio
和pre-commit
:
1 |
|
执行完命令后可以发现pyproject.toml
新增了如下内容:
1 |
|
这块内容表示Poetry
托管的虚拟环境安装了pytest
和pre-commit
的依赖,但是他们是属于dev
组的,在正式情况下不会被使用,这对于导出依赖时非常有作用。
接下来先检查项目的代码格式,首先创建.pre-commit-config.yaml
文件,并输入如下内容
1 |
|
然后执行如下命令:
1 |
|
其中第一个命令是为项目进行git初始化,第二个命令是执行代码检查。
如果出现
ModuleNotFoundError: No module named '_sqlite3'
错误,可以访问No module named _sqlite3了解如何解决。
执行完代码检查后,在tests
目录里面创建一个名为test_demo.py
文件,并输入如下内容:
1 |
|
接着运行poetry run pytest --capture=no -v
执行测试结果:
1 |
|
发现测试正常,接下来可以生成项目的依赖,使其他没有使用Poetry
的环境也可以读取到项目的依赖,对应的命令如下:
1 |
|
其中第一条命令是生成正常使用下的依赖,第二条命令是包含测试环境的依赖。
5.打包与发布
如果这个项目想发到PyPi
供别人使用,那么可以先打包项目再发布到PyPi
中,这时候需要先修改pyproject.toml
中version
的值,比如把它改为0.0.2
,再通过poetry builld
和poetry publish
命令发布。
当然,除了发布到PyPi
外,还可能把项目的代码发布到Github
中,同时为了让开发者快速的找到对应的版本,往往会给当前的commit
打上对应的tag,这就代表着我们必须保证version
中的值与tag
是一致的,此外,项目中demo/__init__.py
也需要添加如下内容:
1 |
|
使得别人在引用这个项目时知道项目的版本号是多少,这样一来每次做项目升级的时候需要同时修改三处地方的版本号,非常折腾,为了省心省力,可以采用Poetry
的一个插件–poetry-dynamic-versioning来解决这个问题。
首先是通过命令:
1 |
|
向Poetry
安装插件,然后向pyproject.toml
添加如下内容:
1 |
|
接着把pyproject.toml
文件中的build-system
块替换为如下内容:
1 |
|
最后把pyproject.toml
和demo/__init__.py
中的版本号改为"0.0.0"
(这是poetry-dynamic-versioning
的一个动态版本号占位符)
一切准备就绪后可以执行如下命令进行代码提交以及打上对应的版本tag:
1 |
|
接下来执行poetry build
对项目打包:
1 |
|
通过命令可以发现包的版本正好是我们提交的tagv0.0.2
中的0.0.2
,如果找到包里面的demo/__init__.py
的文件,可以发现文件中存在如下一行代码:
1 |
|
其中__version__
的值与tag
一样。
打包完成后就可以把包传到PyPi
了,不过在第一次上传之前需要通过如下命令配置自己的PyPi
账户信息:
1 |
|
最后通过poetry publish
命令即可把包传到PyPi
中
6.Poetry的pre-commit
从上面的流程可以发现Poetry
为我们带来方便的虚拟环境管理和依赖管理,但有些时候仍然需要我们调用poetry update
来确定依赖有及时更新以及通过poetry export
来导出依赖,这时可以通过pre-commit-config
来确保提交代码的时候能执行自动执行poetry update
和poetry export
等语法。
第一步先向.pre-commit-config.yaml
追加如下内容:
1 |
|
并执行如下命令:
1 |
|
验证pre-commit
是否正常执行。
7.总结
至此就可以享受Poetry
为我们带来的便利,只要简单几部操作就可以完成虚拟环境的使用和依赖管理,但是本文还有一些内容没有介绍,可以通过官方文档了解Poetry
的更多功能。
``
- 本文作者:So1n
- 本文链接:http://so1n.me/2022/11/23/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8Poetry(1.2+)%E7%AE%A1%E7%90%86Python%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!