Files
pnpm/.changeset/python-indexes-and-rules.md
T
Zoltan Kochan b3da608b5b feat(config): name the ecosystem a registry serves (#15054)
pnpm/pnpm#15043 gave the programs pnpm downloads one setting. This does the
same for the registries it downloads packages from, which were three
settings sharing neither a name nor a shape: `registry` / `registries`,
`python.indexUrl` with `python.extraIndexUrls`, and `cargo.indexUrl`.

A `registries` entry now names the ecosystem it serves:

    registries:
      https://internal.example/simple/:
        ecosystem: pypi
      https://pypi.org/simple/:
        ecosystem: pypi
      https://index.crates.io:
        ecosystem: cargo

`ecosystem` is absent on an npm registry, so every entry written before
there was anything else to serve means what it did.

An ecosystem with several indexes searches them in the order declared, and
the first index that has a package supplies it. `registries` is an
`IndexMap` for that reason: `python.extraIndexUrls` was a list, so a
URL-keyed `BTreeMap` would have handed the search order to URL spelling.
uv marks one index `default = true` and gives it lowest priority wherever
it sits; pnpm reads position instead, because one rule is easier to hold
than two.

A URL serves whatever the last layer to declare it says, and loses every
role an earlier layer gave it. Each layer's `registries` is validated on
its own, so without that rule one URL could be an npm registry to the
machine and a PyPI index to the repository at once.

Credentials are the point. `registry`, `cargo.indexUrl` and
`tools.node.mirror` all resolved credentials by origin from the machine's
auth sources; `python.indexUrl` read them only from an inline `user:pass@`
in the URL. A private PyPI index was therefore the one package source in
pnpm whose password had to be written into the committed
`pnpm-workspace.yaml`. `registries` refuses a credential in a key or a
field, so moving Python indexes there settles it the way it is settled
everywhere else, and deletes the machinery Python had grown for the inline
form: the `IndexAuth` route hook, `validate_index_credentials`, and
`ERR_PNPM_CONFLICTING_PYTHON_INDEX_CREDENTIALS`.

One behavior change follows from that. The old code picked a credential by
longest-matching declared index, so a credentialless index below another
withheld its parent's credentials. npm matches on auth entries instead, so
a credential configured for `//host/simple/` reaches
`//host/simple/public/`, and the machine narrows it by configuring the
narrower path. The test named for the old rule is replaced by one asserting
what this model guarantees: a credential does not travel to an index on
another origin.

The word and its values are the repository's own: pnpr's registry config
already spells `ecosystem: cargo` and `ecosystem: pypi`. The enum is not,
because pnpr's carries `oci` too and pnpm installs from no OCI registry, so
accepting it would be a value pnpm parses and then refuses further in. The
two agree on the wire.

`python.indexUrl`, `python.extraIndexUrls` and `cargo.indexUrl` have not
been released, so they are gone rather than deprecated.

Related to pnpm/pnpm#14945
2026-09-18 13:21:54 +02:00

404 B

pacquet
pacquet
minor

Python installs can resolve from several indexes. A registries entry that names ecosystem: pypi declares one, and they are searched in the order declared.

python.overrides and python.constraints pin the versions a resolution may pick. pnpm reads uv's own overrides and constraints from pyproject.toml too pnpm/pnpm#14945.