写点什么

用 Pixi 管理 Python 项目:打通 Conda 和 PyPI 的边界

作者:肩塔didi
  • 2025-08-11
    德国
  • 本文字数:4126 字

    阅读完需:约 14 分钟

用 Pixi 管理 Python 项目:打通Conda 和 PyPI 的边界

管理 Python 的环境和依赖一直是个让人头疼的问题,这一点从多年来层出不穷的 Python 包管理工具可见一斑:poetry,condamicromamba , hatch , pdmuv…… 不胜枚举。这些工具分散在 Conda 和 PyPI 两大生态中,很多开发者都遇到过:


有些包只在 Conda 找得到,有些只能在 PyPI 安装,两头切换非常麻烦。


Pixi 作为一款支持多语言的包管理器,希望把这两个生态无缝衔接起来:


无论是 Conda 包(通过 rattler 库),还是 PyPI 包(通过与 uv 的集成),都可以在同一个项目里一站式使用。


我们的目标是:打破 Conda 和 PyPI 的壁垒,让它们可以同时使用、互相补充。

这和我有什么关系?

如果你是 Python 开发者,但愿意跳出 PyPI 的“舒适圈”,去了解一下 Conda 生态,你会发现其实有不少实用的优势:


  • 在隔离环境里管理系统级依赖 —— 比如 SDL、OpenSSL 等,直接用 Conda 配好,省去自己折腾。

  • 方便管理非 Python 依赖 —— 如果你的项目需要 Node、npm、CMake、编译器等工具,用 Conda 一起打包,环境更干净。

  • 用 system-requirements(虚拟包)让硬件和环境需求更清晰可控 ——

  • 比如项目需要 CUDA,加到锁文件里,Pixi会在安装时自动匹配正确的版本。

  • pixi add pytorch 时,Pixi 会根据系统自动选 CPU 或 GPU(以及合适的 CUDA 版本);

  • 相比手动执行pip(pip3 install torch --index-url https://download.pytorch.org/whl/cu118),显然前者更省心。


更重要的是,就算有了这些新特性,你还可以继续延用熟悉的 PyPI 项目结构来管理依赖,同时按需接入 Conda 生态,二者不冲突。


Pixi 能带来什么?

除了最新的功能更新,使用 Pixi 管理 Python 项目时,你还会自动获得:


  • Python 解释器的安装与管理:按项目独立管理,支持所有主流平台。

  • 跨平台依赖锁定:为每个主要平台分别锁定依赖,保证可复现性。

  • 任务系统(带缓存):在项目里可以高效执行自定义任务,自动缓存避免重复工作。

  • 多环境支持: 为同一个项目创建多个环境,灵活切换不同依赖组合(例如不同 Python 版本,或 CUDA / 非 CUDA 环境),并支持各自独立的任务配置。

有什么新变化?

在之前的版本里,Pixi 还有一些尚未支持的功能,可能会让用户在切换到 Pixi 时遇到一些不必要的阻碍。


在最新版本中,我们增加了以下新特性:


  • 支持同时使用 pyproject.toml pixi.toml作为 manifest 文件, 更贴合 Python 社区的主流习惯。

  • Pixi 支持从 PyPI 安装源依赖,包括可编辑安装(editable installs)。

  • 支持更完善的 PyPI-Conda 映射功能,如果某个包已在 Conda 环境中可用,就会自动跳过重复安装。


下面是这些新功能的详细介绍:

Pyproject.toml 支持

在最初设计 Pixi 时,我们引入了 pixi.toml 作为 manifest 文件。


之所以没有直接用 pyproject.toml ,是因为 Pixi 不仅仅支持 Python,还支持多种编程语言。


然而对 Python 开发者来说 —— 甚至是 Conda 用户 —— 大家普遍习惯使用 pyproject.toml


Pixi 0.18.0 开始,我们正式推出了对 pyproject.toml 的支持!


对于现有项目,不需要做任何改动,因为 pixi.toml 会优先生效。


所有 Pixi 的独有功能都放在 [tool.pixi.*] 里(pyproject.toml 用户应该对此很熟悉)。

PyPI 源依赖

我们现在支持 直接 URL 依赖(direct url dependencies),即允许直接指定 git 仓库、wheel 文件或 tar.gz 包作为依赖来源。

例如,使用 pixi.toml


requests = { git = "https://github.com/psf/requests.git", rev = "0106aced5faa299e6ede89d123..." }
复制代码


或者使用 pyproject.toml


[project]dependencies = ["flask @ git+ssh://git@github.com/pallets/flask@b90a4f1f4a370e92054b9cc9db0..."]
复制代码


使用 pyproject.toml 进行可编辑安装(editable install):


[tool.pixi.pypi-dependencies] # 本地路径,会以可编辑模式安装你的项目test_project = { path = ".", editable = true }
复制代码


如果使用 pixi.toml,则需要去掉 tool.pixi 前缀。

PyPI ➡️ Conda 映射

Because a lot of python conda packages are repackaged python projects. They can be used interchangeably as dependencies.


你通过 Conda 安装的很多包(例如 conda install pandas),其实最初是从 PyPI(Python 包索引)发布的。这些原生的 PyPI 包,经过再处理,被打包成 Conda 格式(如 .conda 或 .tar.bz2),从而能在 Conda 环境中顺利安装和使用。(译者解释)

换句话说,Conda 与 PyPI 之间本质上是有桥梁的,只是这个桥梁并非自动构建 —— 需要社区开发者主动维护和转换包格式。 这也是我们构建 Pixi 的初衷之一:

更顺滑地连接 PyPI 和 Conda 两大生态系统,让用户不必再因为“某个包只在 PyPI/Conda 上有”而手动切换工具链。

有时候会出现这种情况:你安装的某个 Conda 包是 PyPI 包的依赖项。例如,你已经通过 Conda 安装了 click 包,同时又需要使用 flask 这个 PyPI 包,而 flask 依赖 click

遇到这种场景,可以这样写 pixi.toml,简单清晰:


[project]name = "test"version = "0.1.0"description = "测试 PyPI 和 Conda"authors = ["Tim de Jager <tim@prefix.dev>"]channels = ["conda-forge"]platforms = ["osx-arm64"]
[tasks]
[dependencies]# We depend on click as conda dependencyclick = "*"
[pypi-dependencies]# flask also depends on click, as a pypi dependencyflask = "*"
复制代码


Pixi 中,我们会把 Conda 里的 click 包作为 flask 的依赖来使用,也就是用 Condaclick 来覆盖掉来自 PyPIclick


另外,译者在这里也补充整理了常见的几种 case,方便大家理解映射机制。一句话概括: Pixi 会默认优先选择 Conda 版本。


case 1,同名包,Conda 包覆盖 PyPI 包。

case 2: 同名包版本冲突。这里存在两个同名包的包版本冲突:

  • pypi-seaborn@1.0.0 vs pypi-seaborn@2.0.0

  • conda-pandas@1.0.0vsconda-pandas@2.0.0

Pixi 的策略是:只保留一个版本。根据用户选择的 Conda 包版本,反向去选择要安装的 PyPI 包版本。如果用户选择了 conda-pandas@1.0.0,则安装的是依赖conda-pandas@1.0.0pypi-seaborn@1.0.0pypi-seaborn@2.0.0conda-pandas@2.0.0 则被排除在外。

以前我们用过 grayskull 映射工具来做这件事,👉 Grayskull。不过,grayskull 的映射 有一个限制:需要你手动维护—为了匹配不同包的命名,你必须手动把要用的包添加到配置文件里。


所以为什么不进一步把整个流程完全自动化呢?


我们分析了 超过 1,700,500 个 conda-forge 的包,并且每小时都会自动更新,追踪新包。我们会根据 conda 包的路径信息,自动提取出对应的 Python 包名和版本。通过这一策略,我们额外识别出了 3,807 个新包例如(redisgraph-py , scikit-geometry, cloudpathlib-s3等)。Conda 包与 PyPI 包的映射准确率提升了 **24.66%。**这个策略带来了两个显著优势:


  1. 适用于所有 Conda Channel,无需手动维护映射列表。这意味着我们不再依赖静态配置,而是可以动态地处理不同来源的包。

  2. 有效避免同名包的混淆。很多时候,Conda 和 PyPI 上的包虽然名字一样,实际却完全不同。比如:

  3. 一个典型的例子是pandoc—— Conda 上的 pandoc 实际指的是 Haskell 库,而在 PyPI 上,pandoc 是另一个完全不同的 Python 包。


而如果不做映射处理,容易被误认为是同一个包,从而引发一系列问题。


在 Pixi,我们非常重视开发者体验,也尽量减少那些“意外惊喜”(毕竟生活里,惊喜最好只是来自一杯好咖啡 ☕️😂)


我们包映射系统非常智能,这类问题都能被正确识别和处理 —— 两个pandoc都可以被准确区分、正确安装。


👉 点击这里看看我们是怎么做的(parselmouth 项目)


我们还整理了一些与 Grayskull 映射的对比数据 👇


示例演示

下面的示例会展示前文提到的所有功能点。以下面的文件结构为例:


example_project├── pixi.lock├── pyproject.toml└── test_project    ├── __init__.py    └── module.py
复制代码


我们可以创建一个 pyproject.toml


[build-system]requires = ["hatchling"]build-backend = "hatchling.build"[project]name = "test_project"version = "0.1.0"requires-python = ">=3.9"dependencies = ["rich"]# We need to know the platforms for the locking per platform# as well as the conda channels, this is where we get the python# executable from[tool.pixi.project]name = "test_project"channels = ["conda-forge"]platforms = ["linux-64"][tool.pixi.pypi-dependencies]# A local path, which installs your project in editable mode.test_project = { path = ".", editable = true }[tool.pixi.tasks]# A task to run the python module.start = "python -c 'from test_project import module; module.hello()'"[tool.pixi.dependencies]rich = ">=13.7.1,<13.8"
复制代码

使用下面这个模块:

module.py

from rich import print
def hello(): print('[italic green]Hello World![/italic green] I am a [bold cyan]Pixi[/bold cyan] install!')
复制代码


要运行这个示例,只需执行:


pixi run start
复制代码


这条命令会自动解析、安装 Conda 和 PyPI 的依赖,并执行 start 任务。


使用pyproject.toml 时,Pixi 会读取 requires-python 并据此匹配 Python 解释器的版本。


[project]# 将会从 conda-forge 安装 >= 3.9 的版本requires-python = ">=3.9"
复制代码


pyproject.toml 中的依赖会被 Pixi 当作 PyPI 依赖来解析:


[project]dependencies = ["rich"]
[tool.pixi.dependencies]rich = ">=13.7.1,<13.8"
复制代码


如果你同时在 CondaPyPI 都指定了同一个依赖,Pixi 会默认优先选择 Conda 的依赖。


结语

我们希望通过这个新版本,进一步缩小 PyPI 和 Conda 生态之间的差距


无论你是不是 Python 开发者,是否使用过 Conda,都值得试试把 Pixi 加入你的工具箱


如果你对打包(packaging)有任何问题,欢迎随时通过社交平台找到我们,我们非常乐意与你交流、一起解决问题!

你可以通过以下方式联系我们:

最后,特别感谢我们的开源贡献者 Olivier Lacroix,他完成了大部分 pyproject.toml 的工作 —— 我们非常感谢他的卓越贡献!

发布于: 刚刚阅读数: 4
用户头像

肩塔didi

关注

还未添加个人签名 2018-05-29 加入

还未添加个人简介

评论

发布
暂无评论
用 Pixi 管理 Python 项目:打通Conda 和 PyPI 的边界_机器学习_肩塔didi_InfoQ写作社区