PyPI dependencies#

This guide walks through adding PyPI packages to a conda-workspaces project, including versioned dependencies, editable local packages, and what to install for everything to work.

Manifest compatibility with pixi#

The [pypi-dependencies] table uses the same syntax as pixi, so manifests are portable between the two tools. The underlying implementation is different: pixi resolves PyPI packages with its own built-in solver (uv), while conda-workspaces delegates to conda-pypi and conda-rattler-solver through conda’s plugin system.

Prerequisites#

PyPI dependency support requires two conda packages and a channel configuration:

conda install conda-pypi conda-rattler-solver
conda config --set solver rattler
conda config --append channels conda-pypi

conda-pypi translates PyPI package names to their conda equivalents and handles wheel extraction and editable installs.

conda-rattler-solver is the solver backend that can resolve conda and PyPI packages together in a single pass. Since conda-pypi 0.9.0 it is no longer installed automatically, so you need to install it explicitly.

The conda-pypi channel on conda.anaconda.org makes pure Python packages from PyPI available as conda packages. It uses sharded repodata, which requires the rattler solver to read. Without this channel, the solver has no source for PyPI-originated packages.

If conda-pypi or conda-rattler-solver is missing, conda workspace install prints a warning and skips PyPI dependencies.

See also

These tools build on the conda plugin architecture defined in CEP 2 (plugin architecture proposal) and CEP 4 (plugin mechanism implementation). The solver backend plugin hook that conda-rattler-solver uses was introduced by CEP 3 (pluggable solver backends, originally for conda-libmamba-solver). conda-pypi also registers a package extractor plugin that teaches conda how to extract .whl archives, so wheels are installed through the same transaction pipeline as .conda packages.

Adding versioned PyPI dependencies#

Declare PyPI dependencies alongside your conda dependencies in the manifest:

[dependencies]
python = ">=3.10"
numpy = ">=1.24"

[pypi-dependencies]
httpx = ">=0.27"
pydantic = ">=2.0,<3"

PyPI package names are translated to their conda equivalents via the grayskull mapping and merged into the same solver call as conda dependencies. The solver resolves everything together, so conda and PyPI packages cannot conflict.

Install as usual:

conda workspace install

Extras#

PyPI extras are supported with square-bracket syntax:

[pypi-dependencies]
httpx = { version = ">=0.27", extras = ["http2"] }

Per-feature PyPI dependencies#

Just like conda dependencies, PyPI dependencies can be scoped to a feature:

[feature.test.pypi-dependencies]
pytest-httpx = ">=0.30"

[environments]
default = []
test = { features = ["test"] }

Editable local packages#

For local Python packages under active development, use a path dependency with editable = true:

[pypi-dependencies]
my-project = { path = ".", editable = true }

This installs the package in editable (development) mode so that changes to the source code take effect immediately without reinstalling. conda-pypi builds the package into a .conda archive using PEP 517 and installs it into the environment prefix.

Path dependencies can also point to subdirectories in a monorepo:

[pypi-dependencies]
core = { path = "packages/core", editable = true }
api = { path = "packages/api", editable = true }

Editable and path dependencies are handled separately from versioned PyPI dependencies. They are built and installed after the main solver completes, so they do not participate in dependency resolution. Make sure any transitive dependencies your local package needs are declared as conda or versioned PyPI dependencies in the manifest.

Git and URL dependencies#

You can also install packages directly from git repositories or URLs:

[pypi-dependencies]
my-fork = { git = "https://github.com/user/project.git", branch = "main" }
some-wheel = { url = "https://example.com/pkg-1.0-py3-none-any.whl" }

Like editable installs, these are built post-solve by conda-pypi and do not participate in the solver pass.

Troubleshooting#

“conda-pypi is not installed”#

Install it:

conda install conda-pypi

“conda-rattler-solver is not installed”#

Since conda-pypi 0.9.0, the solver backend is a separate package:

conda install conda-rattler-solver

Solve failures with PyPI packages#

If the solver cannot find a PyPI package, check that:

  1. The conda-pypi channel is in your channel list. Add it with conda config --append channels conda-pypi or include it in your manifest’s channels list.

  2. The solver is set to rattler (conda config --set solver rattler). The conda-pypi channel uses sharded repodata that only the rattler solver can read.

  3. The package name is spelled correctly (PyPI names are case-insensitive but conda names use lowercase and hyphens).

  4. The version constraint is satisfiable.

Next steps#