-
Notifications
You must be signed in to change notification settings - Fork 1
Projects
A repository that uses a shared nepenthe environment declares it in its
pyproject.toml. This is a small reference — which environment, which
version — not the environment definition. From it, nepenthe can install the
environment (sync) and check your project's dependencies against it (check).
A nepenthe environment is a pre-solved, versioned, shared artifact: the
producer solves it once and publishes a frozen lock, and every consumer installs
that exact lock. sync therefore installs the published environment as-is — it
does not re-resolve the environment together with your project's
dependencies. That is the whole point: every consumer gets the identical
environment.
check is the seam that keeps the two in sync. It tells you whether what your
project declares in [project.dependencies] is compatible with the environment
you reference, so you catch drift before it bites.
Add a [tool.nepenthe] section to your pyproject.toml:
[project]
name = "my-app"
dependencies = [
"numpy>=2",
"requests",
]
[tool.nepenthe]
environment = "myenv" # required: which published environment
registry = "file:///srv/nepenthe" # required: where it is published
version = "1.3.0" # optional: label (default "latest")
platform = "linux-64" # optional: defaults to the current platform
python = "3.11" # optional: the python axis value
variant = "cpu" # optional: the variant axis value
prefix = ".venv" # optional: install location (default ".venv")version accepts a label: latest, an exact version (1.3.0), or a range
(>=1.2,<2).
nepenthe sync # reads ./pyproject.toml
nepenthe sync --project path/to/pyproject.toml
# synced myenv (linux-64) at .venv — 312 packagessync resolves the version label against the registry, pulls the lock, and
installs it into the prefix — no conda required. Re-running sync after bumping
version updates the prefix to the new release. This is how you "register" the
environment: pin it once in pyproject.toml, then sync in CI or on a new
machine to get the exact same base every time.
nepenthe check # reads ./pyproject.toml
nepenthe check --platform osx-arm64
# [ok] numpy>=2 (env pins 2.4.6)
# [conflict] pandas>=3 — env pins 2.1.0 (needs >=3)
# [missing] internal-tool — not in env
# [skip] torch @ https://… — not a name+version requirement
# 1 ok, 1 conflict, 1 missing, 1 skippedcheck pulls the environment's lock and compares each [project.dependencies]
entry against the pinned package set:
- ok — the environment pins a version satisfying your requirement.
-
conflict — the environment pins the package, but at a version your
requirement excludes.
checkexits non-zero, so it fails CI. - missing — the environment has no package with that name. This is often fine (a pure-Python dependency you install yourself on top), so it is reported but does not fail the command.
- skip — the entry isn't a simple name+version requirement (e.g. a direct URL), so it can't be checked.
A typical CI step:
nepenthe sync && nepenthe checkimport nepenthe
summary = nepenthe.sync("pyproject.toml") # install the referenced env
report = nepenthe.check("pyproject.toml") # structured compatibility report
if report["has_conflicts"]:
for dep in report["dependencies"]:
if dep["status"] == "conflict":
print(dep["requirement"], "→ env pins", dep["found"])See the Python API for the full surface.
check matches names after PEP 503
normalization (lowercase; -, _, . collapse to -) against the
environment's conda package names. When a PyPI name differs from its conda
counterpart — e.g. opencv-python (PyPI) vs opencv (conda) — check consults
a bundled PyPI→conda name map (derived from conda-forge's
grayskull mapping) so the
dependency still resolves. Only names absent under both spellings report as
missing.
The map is small by design: only the few hundred divergent names are vendored
(the ~12k names that already agree are handled by the direct match). It is
regenerated from the upstream source with a single command — see
Updating the name map below. Even so, treat an
occasional missing as "couldn't confirm" rather than "definitely absent" for an
obscure or very new package.
The vendored table lives at rust/src/data/pypi_to_conda.tsv and is reproducible
from conda-forge's grayskull mapping:
cd rust
cargo run --example regenerate_name_map # fetches, reduces, rewrites the tableThe reducer keeps only divergent pairs and sorts the output, so a regenerated table diffs cleanly — commit it if it changed.
-
No joint resolution with
uv/pixilocks. nepenthe installs the shared base; you manage your project's own dependencies on top (e.g.uv/pipinto the same prefix).checkkeeps the two honest, but nepenthe does not merge or re-solve locks. -
No
pixi.toml/uv.lockimport. The reference lives in[tool.nepenthe]; other lockfiles are independent.
This wiki is autogenerated. To made updates, open a PR against the original source file in docs/wiki.