You could publish a package <pkg>-app that has pinned dependencies, and then tell people to install that instead of <pkg> if they intend to use it as an app?
(And if that works well, then we could consider some metadata on <pkg> that points to <pkg>-app for any tooling that wants to reinterpret the context on behalf of the user.)
How would I upload the additional py.lock for <pkg>-app if PyPI / Warehouse does not support storing such a file?
This approach works for the âembed py.lock inside the wheelâ strategy, but not for the alternative approach of publishing a separate sidecar *.whl.lock file next to the original wheel â potentially also exposed via the simple repository JSON project detail, similar to core-metadata.
To clarify my previous post:
The idea is to publish a py.lock as a sidecar artifact at {file_url}.lock, analogous to {file_url}.metadata / core-metadata, so installers can optionally consume it.
My question is mainly about process: how could such a feature be introduced without first having a full PEP?
For example, would it be acceptable to add support in Warehouse for uploading a py.lock sidecar file associated with an existing wheel â without changing the Simple Repository API initially â so installers could attempt to fetch the lock file when explicitly instructed?
This way, usage would remain completely optional and experimental.
Would that be an acceptable way to go forward from here?
I donât think there is a way as once itâs on Warehouse people will come to rely on it. The PEP will have to demonstrate a desire/need for the feature to motivate it to be served from an index or shipped inside a wheel file.
You can have an entrypoint script for your app that verifies the parts needed for reproducibility prior to then launching the app.
Itâs inelegant, but it allows sidestepping the chicken-egg problem for the version that includes the lockfile in the wheel as a means of demonstrating demand prior to standardization allowing a more elegant version.
It seems like youâre fixated on a particular solution, rather than thinking about just solving your problem.
Wheels/sdists have dependency metadata. By convention, that is unpinned in libraries, but itâs entirely possible to just pin it and publish a regular wheel (either metadata-only, or perhaps you put the CLI in a separate package). When someone installs it, the other packages willmatch exactly what it requires, reproducing the dependencies.
If youâre insistent on creating something different, then you really need to set it up and demonstrate it, before arguing that it should be merged into the existing tool (where it becomes incredibly difficult to change or remove, as Brett says). You donât need a PEP to set up your own index, or to encourage tools to support your index (though some may want it to be a community standard before theyâll support it - that just means you havenât encouraged them enough ).
Or you can use an approach that already exists, already works, doesnât require anyone to change anything more drastic than the one install command that currently doesnât do the thing they want it to do. Iâm not forcing anything, Iâm just ignoring your solution and offering you a much easier way to solve your problem.
A possibly interesting point of prior art here, is that cargo install has a --locked flag that will use the Cargo.lock from the the thing that is being installed instead of using the unlocked dependencies in Cargo.toml.
That ecosystem is different from ours though. IIRC cargo install can only install a single âthingâ, and itâs use case is pretty much entirely installing a CLI into the system, and itâs not part of the regular day to day functionality of writing a Rust project and adding/removing dependencies. cargo install is closer in spirit to something like pipx install.
In python pip/uv/etc install typically accepts multiple things, and it more closely related to something like cargo add than cargo install.
Instead of doing that, you have to somehow build a package with pinned dependencies in its METADATA, there are many ways of doing that. Not exhaustively:
setup.py where the install_requires= is generated from the contents of a requirements.txt file with pinned dependencies. That file can be generated with pip-compile or uv pip compile, for example.