引言
将Python编写的桌面和命令行程序发布到PyPI是一个简单直接的分发方式,PyPI上存放着成千上万的第三方程序包。这些程序包里很多都带有可以直接运行的脚本,但要使用它们,你得对Python的生态圈有一定的了解。有了pipx这个工具,你可以在不影响全局Python解释器的情况下,安全地安装和运行这些应用程序。
通过本教程,你将掌握以下技能:
- 把Python包索引(PyPI)打造成一个应用商店
- 不通过Python直接调用就能运行已安装的应用程序
- 防止不同应用间的依赖性冲突
- 在临时环境中尝试试用应用程序
- 管理已安装的应用及其运行环境
为了更好地利用本教程,你需要对命令行操作有一定的熟悉度。特别是,掌握如何在项目中管理Python版本、创建虚拟环境和安装第三方模块,这些技能将对你大有裨益。
管理应用
在本节中,你将通过 pipx 执行多项应用管理任务。安装了 Python 应用后,你可能想要列出这些应用、升级或降级它们的版本,以及卸载不再需要的应用。这些操作与使用传统 pip 管理 Python 包的方式相似。
列出已安装的应用 你无需记住每个已安装 Python 包的具体入口点。任何时候,你都可以通过在终端输入 pipx list
来列出所有已安装的应用及其命令。
$ pipx list
venvs are in /home/user/.local/share/pipx/venvs
apps are exposed on your $PATH at /home/user/.local/bin
manual pages are exposed at /home/user/.local/share/man
package ipython 8.22.1, installed using Python 3.12.2
- ipython
- ipython3
- man1/ipython.1
package mypy 1.8.0, installed using Python 3.12.2
- dmypy
- mypy
- mypyc
- stubgen
- stubtest
package pandas 2.2.1, installed using Python 3.12.2
- f2py
package poetry 1.8.0, installed using Python 3.12.2
- poetry
package ruff 0.2.2, installed using Python 3.12.2
- ruff
AI 代码解读
上述命令的输出显示了 pipx 管理的虚拟环境的位置,一个包含指向可执行文件的符号链接的文件夹,以及一个包含一些包提供的手册页作为文档的文件夹。
输出的其他部分包括了已安装的包、它们的版本以及这些包关联的虚拟环境中使用的 Python 解释器。此外,每个包还列出了你可以在终端中调用的命令。
如果你只想显示包名和版本号,可以使用 --short
选项:
$ pipx list --short ipython 8.22.1 mypy 1.8.0 pandas 2.2.1 poetry 1.8.0 ruff 0.2.2
AI 代码解读
每个软件包都配有一个专属的虚拟环境,以便单独使用。如果你想了解底层虚拟环境的更多细节,包括解析后的绝对路径信息,可以使用 --json
参数:
$ pipx list --json
{
"pipx_spec_version": "0.1",
"venvs": {
"ipython": {
…},
"mypy": {
…},
"pandas": {
…},
"poetry": {
…},
"ruff": {
"metadata": {
"injected_packages": {
},
"main_package": {
"app_paths": […],
⋮
"package_version": "0.2.2",
"pip_args": [],
"suffix": ""
},
"pipx_metadata_version": "0.3",
"python_version": "Python 3.12.2",
"venv_args": []
}
}
}
}
AI 代码解读
正如其名所示,这个命令会以 JSON 格式返回结果,非常适合用于自动化任务以及将 pipx 与其他工具集成到你的工作流程中。由于 JSON 具有机器可读的特性,你可以通过编程方式获取包的版本、位置和依赖关系等详细信息。
一旦你了解了哪些应用被安装在系统中,你就可以执行它们的命令或调整它们的虚拟环境。
升级
如果你想使用常规的 pip 工具将现有的 Python 包升级到最新版本,你会运行带有 --upgrade 标志的 pip install 命令。而在使用 pipx 时,你可以通过 upgrade 子命令来完成相同的升级操作:
$ pipx upgrade ruff upgraded package ruff from 0.0.292 to 0.2.2 (location: /.../venvs/ruff) $ pipx upgrade ruff ruff is already at latest version 0.2.2 (location: /.../venvs/ruff)
AI 代码解读
这个操作会定位到相应的虚拟环境,并利用其中的 Python 解释器执行 python -m pip install --upgrade ruff
命令。这样做很便捷,因为你无需自己寻找并手动激活正确的虚拟环境。
当你通过 pipx 安装了许多不同虚拟环境中的包时,这个过程也相对简单。如果手动逐个升级这些包会是一项庞大的工作。幸运的是,你可以通过 upgrade-all
子命令一次性将所有包升级到它们的最新版本:
$ pipx upgrade-all upgraded package ruff from 0.0.292 to 0.2.2 (location: /.../venvs/ruff) upgraded package poetry from 1.2.2 to 1.8.0 (location: /.../venvs/poetry) upgraded package mypy from 1.6.1 to 1.8.0 (location: /.../venvs/mypy) upgraded package ipython from 7.34.0 to 8.22.1 (location: /.../venvs/ipython) upgraded package pandas from 2.1.1 to 2.2.1 (location: /.../venvs/pandas)
AI 代码解读
执行这个命令可以确保你安装的所有包都是最新版本。
如果你不想总是使用最新版本,而只是想将某个包升级到特定版本,或者你想要降级某个包而不是升级,你将在下一节中找到实现这两种操作的方法。
降级应用到特定版本 pipx 没有提供直接降级已安装包的命令。当你尝试安装一个你之前已经安装过的 Python 包的特定旧版本时,pipx 会阻止这一操作。同时,它会告诉你正确的处理方法:
$ pipx install ruff==0.0.292
'ruff' already seems to be installed. Not modifying existing installation
⮑ in '/home/user/.local/share/pipx/venvs/ruff'.
⮑ Pass '--force' to force installation.
AI 代码解读
在 pip 中,你可以通过指定需求说明符来降级一个包,但在 pipx 中不能这样做。相反,你需要使用 --force
标志来指示工具可以修改现有的虚拟环境:
$ pipx install --force ruff==0.0.292
Installing to existing venv 'ruff'
installed package ruff 0.0.292, installed using Python 3.12.2
These apps are now globally available
- ruff
done! ✨ 🌟 ✨
AI 代码解读
pipx 工具在内部将 --force
参数转换为 --force-reinstall
并传递给 pip。这意味着 pip 会重新安装包,即使它们已经在目标版本中。
最终,如果没有任何包的版本能满足你的要求,可能就需要完全卸载该包并寻找其他替代品了。
卸载虚拟环境
要一并移除 Python 包及其由 pipx 管理的虚拟环境,你可以使用命名直观的 uninstall
子命令:
$ pipx uninstall ruff uninstalled ruff! ✨ 🌟 ✨
AI 代码解读
这个操作还会移除与这些包相关的手册页和 shell 中的符号链接,这意味着你将无法再使用它们。
如果你想一次性卸载所有包,pipx 也提供了相应的解决方案:
$ pipx uninstall-all uninstalled poetry! ✨ 🌟 ✨ uninstalled mypy! ✨ 🌟 ✨ uninstalled ipython! ✨ 🌟 ✨ uninstalled pandas! ✨ 🌟 ✨ $ pipx list nothing has been installed with pipx 😴
AI 代码解读
现在,你可以重新开始,像一张白纸一样!但如果你经常使用 pipx 安装的许多工具,请小心使用这个命令,因为重新安装它们可能需要一些时间。
虚拟环境
在接下来的几个部分中,你将学习如何修改 pipx 管理的虚拟环境。在这个过程中,你将看到一些在你的开发工作流程中可能遇到的实用案例。
依赖项
使用 pipx 而不是 pip 的一个主要好处是,pipx 为你管理虚拟环境,确保安装的包能够正确隔离。一方面,pipx 提供了方便和安全保障,但另一方面,它似乎阻止了你对这些虚拟环境的调整。有时,你可能需要对这些环境有一定的控制。
例如,如果你按照官方文档推荐的方式使用 pipx 安装了 Poetry,那么你可能在稍后需要安装一个可选插件,比如 poetry-plugin-export。在这种情况下,可以使用 pipx inject
命令:
$ pipx inject poetry poetry-plugin-export poetry-plugin-bundle
injected package poetry-plugin-export into venv poetry
done! ✨ 🌟 ✨
injected package poetry-plugin-bundle into venv poetry
done! ✨ 🌟 ✨
AI 代码解读
inject
子命令需要你提供之前安装过的原始包名,比如 poetry
,然后是你想添加的一个或多个额外依赖项的列表。这个包名用于识别 pipx 为你管理的相应虚拟环境。
为了验证这些新依赖项是否已正确添加到虚拟环境,你可以使用 pipx runpip
命令。这个命令允许你在应用的虚拟环境中执行任意的 pip 命令:
$ pipx runpip poetry list | grep poetry poetry 1.8.0 poetry-core 1.9.0 poetry-plugin-bundle 1.3.0 poetry-plugin-export 1.6.0
AI 代码解读
这里,你运行 pip list
命令在 Poetry 的虚拟环境中,以获得所有已安装依赖项的完整清单。接着,你将该命令的输出结果进行筛选,仅展示那些名称中包含“poetry”这个词的包。
你也可以利用 runpip
命令来升级或降级 pipx 管理的虚拟环境中的依赖项,并且通过将依赖项版本锁定到一个需求文件中来固定它们的版本号:
$ pipx runpip poetry install poetry-plugin-export==1.3.1 $ pipx runpip poetry install poetry-plugin-export --upgrade $ pipx runpip poetry freeze > requirements.txt
AI 代码解读
尽管技术上你可以使用 runpip
命令来移除受管虚拟环境中的依赖项,但使用 pipx 提供的更直接的 uninject
子命令会是一个更好的选择:
$ pipx uninject poetry poetry-plugin-export Uninjected package poetry-plugin-export ⮑ and its dependencies from venv poetry ✨ 🌟 ✨
AI 代码解读
如果你使用 pip 手动卸载某个依赖项,可能会遗留下一些间接或传递性的依赖。而 pipx uninject 会自动处理这些依赖,确保不会留下任何未使用的依赖项。
使用 pipx inject 的另一个场景是,当你需要在基于 Python 3.12 或更高版本的虚拟环境中执行 mypyc
命令时。Mypy 的 C 扩展模块编译器需要 setuptools,但从 Python 3.12 版本开始,setuptools 不再包含在 Python 中。截至本文撰写时,mypy 并未将 setuptools 列为依赖项,因为它原本预期 setuptools 会随 Python 一起提供。因此,直接在终端运行 mypyc 会因为缺少 setuptools 而报错:
$ mypyc
Traceback (most recent call last):
...
ModuleNotFoundError: No module named 'setuptools'
AI 代码解读
pipx Inject 命令可以解决这个问题,让您将缺少的依赖项安装到正确的虚拟环境中:
$ pipx inject mypy setuptools
injected package setuptools into venv mypy
done! ✨ 🌟 ✨
AI 代码解读
现在有了 setuptools,您可以运行 mypyc 来编译基于类型注释的 Python 代码的 C 扩展模块:
$ cat adder.py
def add(x: float, y: float) -> float:
return x + y
$ mypyc adder.py
running build_ext
building 'adder' extension
creating build/temp.linux-x86_64-cpython-312
creating build/temp.linux-x86_64-cpython-312/build
gcc -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC ...
creating build/lib.linux-x86_64-cpython-312
gcc -shared -L/home/user/.pyenv/versions/3.12.2/lib -Wl,-rpath,/home/...
copying build/.../adder.cpython-312-x86_64-linux-gnu.so ->
AI 代码解读
当您将生成的动态链接库导入 Python REPL 会话并调用 add() 时,该函数似乎被编译到您平台的本机代码中:
>>> import adder
>>> adder
<module 'adder' from '/home/user/adder.cpython-312-x86_64-linux-gnu.so'>
>>> adder.add
<built-in function add>
>>> adder.add(3.14, 2.72)
5.86
AI 代码解读
作为另一种选择,你不必向受管的虚拟环境注入缺失的依赖项,而是可以将 Python 版本降级到自带 setuptools 的版本。这是你接下来将执行的操作。
指定版本
通常,pipx 会使用你安装 pipx 时所用的 Python 解释器中的 venv 模块来创建新的虚拟环境。具体来说,如果你是通过 python -m pip install pipx
安装的,那么 pipx 会使用你当前激活环境的解释器。如果你使用的是操作系统的包管理器,那么它可能会使用全局 Python 或另一个可能已过时的独立解释器。
你可以在两种情况下指定使用不同的默认 Python 解释器:
- 在用 pipx 安装某个 Python 包之前
- 在已经安装了一个包之后作为补救措施
第一种情况更为简单,因此你会首先考虑它。如果你想要了解如何在已存在的虚拟环境中更改 Python 版本,请查看下一节内容,那里会介绍如何使用 reinstall 子命令。
pipx run
和 pipx install
命令都支持 PIPX_DEFAULT_PYTHON
环境变量,你可以通过它来指定默认的 Python 解释器:
$ export PIPX_DEFAULT_PYTHON=/path/to/python-3.13.0a4/bin/python3
$ pipx run ipython
Python 3.13.0a4 (tags/v3.13.0a4:9d34f60783, Feb 26 2024, 13:03:08) [GCC 13.2.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.22.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
AI 代码解读
在这里,你通过环境变量指定了一个 Python alpha 版本的自定义构建路径,这个版本是你从 GitHub 克隆并自行编译的。接着,利用 pipx,你在基于这个 alpha 版本的临时虚拟环境中启动了一个 IPython 会话,IPython 启动时的消息确认你正在运行的是 Python 3.13.0a4 版本。
此外,pipx run
和 pipx install
命令还提供了一个可选的 --python
参数,允许你为特定的虚拟环境指定 Python 解释器。这个参数可以接受以下几种值之一:
- 文件路径:你文件系统中 python 可执行文件的绝对路径
- 可执行文件:如果该名称在你的 PATH 环境变量中,则为可执行文件的名称
- 版本:Windows 上 Python Launcher 能够识别的 Python 版本
如果你已经配置了 pyenv 或 pyenv-win,你可以在系统级解释器旁边安装一个旧版本的 Python,以及其他你可能已经安装或自行编译的解释器。然后,你应该找到 pyenv 存储 Python 版本的目录中的相应 python 可执行文件。或者,你可以临时将新安装的 Python 设置到你的 shell 中,并查找其可执行文件的路径:
$ pyenv install 3.11.8
Downloading Python-3.11.8.tar.xz...
-> https://www.python.org/ftp/python/3.11.8/Python-3.11.8.tar.xz
Installing Python-3.11.8...
Installed Python-3.11.8 to /home/user/.pyenv/versions/3.11.8
$ pyenv shell 3.11.8
$ pyenv which python
/home/user/.pyenv/versions/3.11.8/bin/python
AI 代码解读
一旦您知道首选 Python 解释器的完整路径,您可以在安装 mypy 或其他包时将其传递给 pipx:
$ pipx install --python=/home/user/.pyenv/versions/3.11.8/bin/python mypy
installed package mypy 1.8.0, installed using Python 3.11.8
These apps are now globally available
- dmypy
- mypy
- mypyc
- stubgen
- stubtest
done! ✨ 🌟 ✨
AI 代码解读
命令执行结果显示 pipx 已根据指定的 Python 解释器创建了虚拟环境。你可以用 pipx list
命令再次列出已安装的包,以进行再次确认。
奇怪的是,即便你现在已经切换到了一个较旧的 Python 版本,理论上应该在新环境中包含 setuptools,但尝试运行 mypyc
时你还是会遇到之前的错误:
$ pipx runpip mypy list Package Version ----------------- ------- mypy 1.8.0 mypy-extensions 1.0.0 pip 24.0 typing_extensions 4.9.0
AI 代码解读
如你所见,在受管理的虚拟环境中没有 setuptools。原来,pipx 创建的是只包含安装包及其依赖的最小化环境。这是因为 pipx 在运行 venv 模块时使用了 --without-pip 开关,这样就跳过了 pip 和 setuptools 这类包的安装。因此,你需要手动安装 setuptools。
对于你之前用 pipx 安装的应用,你将了解到如何控制它们各自虚拟环境中的 Python 版本。
更改Python 版本
如果你只想更改已安装应用的 Python 版本而不影响其他设置,你可以使用 pipx reinstall 命令。在没有额外参数的情况下执行该命令,它会移除应用及其独立的虚拟环境,并按照你最初设置的选项重新安装。
话虽如此,pipx reinstall 命令也支持 --python 参数,允许你使用任何你喜欢的 Python 版本重新创建已安装应用的虚拟环境:
$ pipx reinstall --python=/path/to/python-3.13.0a4/bin/python3 ipython
uninstalled ipython! ✨ 🌟 ✨
installed package ipython 8.22.1, installed using Python 3.13.0a4
These apps are now globally available
- ipython
- ipython3
These manual pages are now globally available
- man1/ipython.1
done! ✨ 🌟 ✨
AI 代码解读
你现在可以在任何地方通过终端启动 ipython
,它将运行在你用 pipx 指定的 Python 3.13 alpha 4 版本上。
如果你升级了主要的 Python 解释器,并希望使用 --python
选项切换到一个更新的版本,那么用 pipx 重新安装 Python 应用会非常有用。鉴于在虚拟环境中升级 Python 版本是一个常见操作,pipx 提供了另一个便捷的子命令 reinstall-all
,它能够一次性完成所有虚拟环境中的升级或降级操作:
$ pipx reinstall-all --python=python3.12
uninstalled ipython! ✨ 🌟 ✨
installed package ipython 8.22.1, installed using Python 3.12.2
These apps are now globally available
- ipython
- ipython3
These manual pages are now globally available
- man1/ipython.1
done! ✨ 🌟 ✨
uninstalled pandas! ✨ 🌟 ✨
installed package pandas 2.2.1, installed using Python 3.12.2
These apps are now globally available
- f2py
done! ✨ 🌟 ✨
⋮
AI 代码解读
请注意,这个操作会重新安装所有包,哪怕其中一些包已经在使用你期望的 Python 版本。为了避免这种情况,或者保留一些应用的原样,你可以通过 --skip
参数选择性地列出某些包以排除它们:
$ pipx reinstall-all --python=python3.12 --skip poetry pandas mypy
AI 代码解读
确保在继续之前,你 PATH 环境变量中的某个路径下能找到对应的 Python 可执行文件。执行完这个命令后,pipx 会使用你指定的 Python 版本重新安装所有未被明确排除的 Python 应用程序。
总结
现在,你对 pipx 在日常 Python 编程中解决的问题有了很好的理解。你知道了如何安装和配置 pipx,以及如何在不进行安装的情况下使用它。有了这些知识,你可以安全地在隔离的虚拟环境中运行命令行 Python 应用,避免依赖冲突。
在本教程中,你学习了如何:
- 将 Python 包索引(PyPI)转变为应用市场
- 无需显式调用 Python 即可运行已安装的应用
- 避免不同应用间的依赖冲突
- 在临时位置尝试临时应用
- 管理已安装应用及其环境
将 pipx 整合到你的编程工具箱中,无疑会提升你使用 Python 时的工作效率。