# Pre-PEP: Include pylock.toml files inside wheels

**URL:** <https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385>\
**Category:** Packaging\
**Created:** [July 19, 2025, 3:32pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385 "2025-07-19T15:32:24Z")\
**Posts on this page:** 11\
**Page:** 2

<div class="post-metadata">

**Author:** ![notatallshaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/notatallshaw/32/10861_2.png) [@notatallshaw](https://discuss.python.org/u/notatallshaw)\
**Post date:** [July 20, 2025, 4:41am UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/21 "2025-07-20T04:41:25Z")

</div>

> [@sirosen](#):
>
> - How would locking work with this? Would `pip-compile` or a locker have to unpack dists and read their contents, rather than just their metadata?
> - What should a locker (e.g., `uv lock`) do when it finds a “nested lockfile” while trying to _update_, not freshly generate, a lock?
> - How should tools behave when installing packages which have conflicting lockfiles? What if those packages have compatible dependencies? What if they don’t?
> - Should tools ever ignore nested lockfiles? Does that match the intent of the maintainer who put a lockfile into their distribution?
> - When updating/reinstalling a package with a lockfile, are tools expected to do any differential analysis of the lockfiles from before and after the update?

FWIW, to me this proposal is pretty clear about all of these questions:

- It wouldn’t interact with locking, pip-compile shouldn’t look at lock files, it’s resolving libraries for an application, not installing an application
- Nothing, dependencies should be treated as libraries and their lock files ignored
- Follow the lock file specification, i.e. follow the lock file and don’t try to resolve the dependencies
- There should no concept of “nested lock files”, the lock file is for when you are the one primary tool or application, if you are a dependency your lock file isn’t read
- Follow the lock file specification or the default behavior the installer handles this with regular lock files

---

<div class="post-metadata">

**Author:** ![padraic](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/padraic/32/29282_2.png) [@padraic](https://discuss.python.org/u/padraic)\
**Post date:** [July 20, 2025, 8:29am UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/22 "2025-07-20T08:29:18Z")

</div>

> [@pf\_moore](#):
>
> Nobody ever asked for requirements files (with pinned dependencies) to be shipped in wheels. I find it difficult to believe that this use case has suddenly appeared, right when lockfiles get standardised. So I have to ask, what were people doing about this _before_ lock files - and why can’t they carry on doing that?

In practice, probably something similar was being achieved by pinning exact versions in a package’s requirements, even if that is explicitly discouraged.

At my organisation, we currently get there by using a mixture of a lockfile, a dynamic pyproject field and a build plugin (`hatch-requirements-txt`); we export a `uv.lock` file to `requirements.txt`, and that plugin is responsible for translating it into the `Requires-Dist` entries in the wheel metadata. This is because we wanted to support less technical users doing data-science work, ensuring consistency between their local setup and the production environment; just installing our in-house packages is enough to guarantee that.

While that’s a strictly internal use-case, there are definitely cases where libraries or applications for public distribution could also benefit from the guarantees of locking. For example, applications doing numerical analysis probably want to pin dependencies to ensure consistency and reproducibility of results (libraries like scikit-learn for example don’t guarantee reproducible models between minor version changes).

I think what locking offers _over_ just pinning exact dependencies, besides just side-stepping the resolve step, is that they can also include security-related metadata like hashes and annotations.

Edit: Delete line where I hedged way too much about security based on the phrase “However, this PEP does not solve all potential security concerns.”; thank you to @pradyunsg for the clarification.

---

<div class="post-metadata">

**Author:** ![abravalheri](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/abravalheri/32/4990_2.png) [@abravalheri](https://discuss.python.org/u/abravalheri)\
**Post date:** [July 20, 2025, 1:38pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/23 "2025-07-20T13:38:52Z")

</div>

The suggestions from Stephen and Paul seem like a promising way to start experimenting with the possibilities in the tooling space before diving into writing a full standard… It could also be a great way to gather feedback and assess what works best.

> [@sirosen](#):
>
> - Bundle a `pylock.toml` in your package as in-package file data (like `py.typed`, if you need an example) and make a tool which uses that file
> - Use VCS/HTTPS installs from a source repo, and make a tool which looks for `pylock.toml` in the repo root
> - Provide a Project-URL with a link to the associated `pylock.toml` (served/hosted separately)

> [@pf\_moore](#):
>
> One advantage of something like `pipx run https://url/to/pylock.toml [entry_point]` is that it can be implemented _entirely_ as a tool feature, without needing any new standards. That would at least give an indication of how useful the functionality is.

* * *

I’m trying to fully understand the concerns raised, particularly in the light of Stephen’s and Paul’s proposals. It feels like some of these could potentially be addressed within their suggested approaches.

> [@Kound](#):
>
> Because then we loose the package manager feature like, installing a specific version of the application and need to create yet another service to manage and distribute the lock files.  
> The problem I want to solve is how to easily distribute a versioned lock file **without** :
> 
> - writing another package manager
> - and it’s service counterpart
> - teach users how to use it
> - define what a release it and how to sync it with the wheel package release

Regarding these requirements, my thoughts are the following:

> - writing another package manager

In principle it is not necessary to write another package manager. Instead, there are 2 options (a) writing a **tool that wraps existing package managers** or (b) collaborating with maintainers of current tools to incorporate this use case. I imagine a similar effort would be needed even with a PEP.

> - and it’s service counterpart

If we look at Stephen’s comment, using PyPI would be a direct reuse, similar to the proposed PEP, so there might not be a significant difference in that regard. With Paul’s idea, modern code repositories like GitHub already offer somewhat decent ways of distributing files (either viw raw URLs or release artifacts), potentially negating the need for a completely new service.

> - teach users how to use it

My understanding is that users would need to learn specific conventions or standards regardless of whether we pursue a PEP or a tool-based approach. The teaching effort might be somewhat equivalent across all these options. Users would need to be aware of how a “cli call” is translated to a “installation/execution procedure” in either a potential standard or simply a tool-specific convention, as well as how to write/distribute them.

> - define what a release it and how to sync it with the wheel package release

Again, Stephen’s suggestion could leverage PyPI, just like the proposed PEP. For Paul’s concept, GitHub Actions is a good example of how to use platforms like GitHub to specify release versions — this information can often be embedded directly in the URL or via shortcut syntaxes like `actions/setup-python@v5`.

Here is a toy example of a (not necessarily good) way of parsing that information:

```python
import os
import sys
import argparse
from urllib.parse import urlparse

SHORTCUT = {
    "gh": ("https://raw.githubusercontent.com/{repo}/refs/heads/{ref}/pylock.toml", "main"),
    "github": ("https://raw.githubusercontent.com/{repo}/refs/heads/{ref}/pylock.toml", "main"),
    "bitbucket": ("https://bitbucket.org/{repo}/raw/{ref}/pylock.toml", "main"),
    "heptapod": ("https://foxx.heptapod.net/{repo}/-/raw/{ref}/pylock.toml", "branch/main"),
    "file": ("{repo}", ""),
    "http": ("{repo}", ""),
    "https": ("{repo}", ""),
}
DEFAULT = "github"

def locator(file: str) -> str:
    if os.path.isfile(file):
        return file
    if os.path.isdir(file):
        return os.path.join(file, "pylock.toml")
    if file.startswith(("./", "../", "/", f".{os.sep}", f"..{os.sep}", os.sep)):
        raise FileNotFoundError(file)

    parts = urlparse(file)
    template, default_ref = SHORTCUT[parts.scheme or DEFAULT]
    repo, _, ref = file.partition("@")
    return template.format(repo=repo, ref=ref or default_ref)

def parse(args: list[str]) -> tuple[str, str]:
    """
    >>> parse(['hello/world'])
    ('https://raw.githubusercontent.com/hello/world/refs/heads/main/pylock.toml', 'world')
    >>> parse(['hello/world@v5'])
    ('https://raw.githubusercontent.com/hello/world/refs/heads/v5/pylock.toml', 'world')
    """
    parser = argparse.ArgumentParser()
    parser.add_argument("file", help="URL where to find the pylock.toml file")
    parser.add_argument("-e", "--entrypoint", help="Name of the entrypoint to run (must be in the `console_scripts`or `gui_scripts` group)")
    params = parser.parse_args(args)
    directory, _, _ = params.file.replace("pylock.toml", "").partition("@")
    entrypoint = params.entrypoint or os.path.basename(directory)
    address = locator(params.file)
    return (address, entrypoint)

```

(A real implementation could expand on that and actually use APIs instead of template URLs). The advantage of this approach is that it actually increases the possibilities of how to distribute applications (and side steps historical limitations of PyPI like name collisions).

---

<div class="post-metadata">

**Author:** ![pradyunsg](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pradyunsg/32/206_2.png) [@pradyunsg](https://discuss.python.org/u/pradyunsg)\
**Post date:** [July 20, 2025, 1:45pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/24 "2025-07-20T13:45:18Z")

</div>

> [@padraic](#):
>
> security is not an explicit goal of PEP751, but the standard does make good strides in that direction.

Good security defaults is definitely a thing that pylock.toml was explicitly designed for. From the rationale in the PEP:

> The file format should promote good security defaults.

* * *

> [@Kound](#):
>
> On the contrary there is no standardized nor easy way to convert a python package into a full blown app.

Yes, and that’s because it’s an explicitly unsolved problem (as already discussed above).

> [@pf\_moore](#):
>
> I think it will be bad for the packaging ecosystem in the long term.

I share that assessment.

I also feel like we should not solve this problem in the standards until we have a non-standard solution for this problem – namely, if uvx or pipx or some other tool implements the handling of the lock file.

To be very clear, a lockfile encodes specific environments and IMO it doesn’t need to be coupled strongly with a wheel to be able to install your custom package. In fact, you don’t even need the lockfile to end up on PyPI, if you instead have it be something like “fetch the lockfile from URL, install the lockfile’s environment, run `cmd` in the environment” without being coupled with the wheel file or whatnot.

---

<div class="post-metadata">

**Author:** ![Kound](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/kound/32/8195_2.png) [@Kound](https://discuss.python.org/u/Kound)\
**Post date:** [July 20, 2025, 3:27pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/25 "2025-07-20T15:27:06Z")

</div>

After reading some of the replies, I realized the discussion has shifted more toward the topic of _application deployment_.  
Because of that, I’ve rewritten the original post (please have another look before continuing the discussion), starting more strongly from the use cases and clearly limiting the scope.

I’m also considering reaching out to `uv` and `pipx` about supporting lock files included within the package folder itself, not just in the `dist-info` directory.  
(Though to clarify: while there can be multiple package folders, the standard does not forbid placing files in the `dist-info` folder — only subdirectories are reserved.)

* * *

What I still don’t fully understand is:  
**How would a completely optional standard harm the packaging ecosystem?**

I genuinely don’t have your depth of experience, so I’d appreciate any concrete examples or past situations where optional features have caused harm — especially if there’s a story/example you could share. That would really help me understand your concerns better.

* * *

From my perspective (as detailed in the revised proposal), there are several strong reasons to include lock files _inside_ wheels:

- **Security & reliability** : No dependency on external services during installation
- **Reproducibility** : As the build system includes the lock file used to pass tests tests pass, for the most pipelines it is ensured they will work.
- **Simplicity** : It’s easy to associate a lock file with the package it belongs to, and tools (as welll as humans) can find and use it without needing additional APIs, tokens, or infrastructure

* * *

So far, the only downsides I’ve seen mentioned are:

- The confusion between “wheels” and “applications” (which I’ve tried to address more clearly in the rewritten proposal)
- Slightly increased wheel size

If I’ve missed any additional concerns about including a lock file in the wheel, or if there are others you’d like to raise, I’d really appreciate if you could point me to them.

* * *

**P.S.** I’m a slow writer — the initial and revised versions of the proposal took me more than 10 hours in total — so I may only be able to follow up or respond toward the end of the week. Thanks for your patience!

---

<div class="post-metadata">

**Author:** ![oscarbenjamin](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/oscarbenjamin/32/1209_2.png) [@oscarbenjamin](https://discuss.python.org/u/oscarbenjamin)\
**Post date:** [July 20, 2025, 3:40pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/26 "2025-07-20T15:40:48Z")

</div>

> [@Kound](#):
>
> **EDIT** : I completely rewrote the proposal

Please don’t do this. It makes the discussion confusing for anyone reading in future as now the replies are written as replies to something that isn’t there any more. If the proposal is to be completely rewritten then it is better to start a new thread.

---

<div class="post-metadata">

**Author:** ![pradyunsg](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pradyunsg/32/206_2.png) [@pradyunsg](https://discuss.python.org/u/pradyunsg)\
**Post date:** [July 20, 2025, 3:42pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/27 "2025-07-20T15:42:57Z")

</div>

> [@Kound](#):
>
> Why not distribute the lock file separately via URL?

I still think that the arguments made in are very weak. They’re phrased quite persuatively (which LLMs are good at) but they’re not particularly strong arguments.

The need to trust an additional source of truth is not a problem for most users - they’d be willing to trust GitHub or an internal-to-my-company artifact and the fact that certain URLs will be mutable is arguably a feature.

---

<div class="post-metadata">

**Author:** ![Kound](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/kound/32/8195_2.png) [@Kound](https://discuss.python.org/u/Kound)\
**Post date:** [July 20, 2025, 3:46pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/28 "2025-07-20T15:46:15Z")

</div>

> [@oscarbenjamin](#):
>
> Please don’t do this. It makes the discussion confusing for anyone reading in future as now the replies are written as replies to something that isn’t there any more. If the proposal is to be completely rewritten then it is better to start a new thread.

I will revert the changes and start a new thread (and edit this message to point to the new thread).  
@pradyunsg please copy your answer to the new thread once it opened.

---

<div class="post-metadata">

**Author:** ![pradyunsg](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pradyunsg/32/206_2.png) [@pradyunsg](https://discuss.python.org/u/pradyunsg)\
**Post date:** [July 20, 2025, 3:46pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/29 "2025-07-20T15:46:40Z")

</div>

> [@Kound](#):
>
> @pradyunsg please copy your answer to the new thread once it opened.

Sure, will do.

Feel welcome to address it as well, if you are creating a new thread and have the ability to do so.

---

<div class="post-metadata">

**Author:** ![Kound](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/kound/32/8195_2.png) [@Kound](https://discuss.python.org/u/Kound)\
**Post date:** [July 20, 2025, 3:58pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/30 "2025-07-20T15:58:32Z")

</div>

Please continue discussion in [Pre-PEP: Add ability to install a package with reproducible dependencies](https://discuss.python.org/t/pre-pep-add-ability-to-install-a-package-with-reproducible-dependencies/99497)

(can somebody lock this thread pls?)

---

<div class="post-metadata">

**Author:** ![davidism](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/davidism/32/3295_2.png) [@davidism](https://discuss.python.org/u/davidism)\
**Post date:** [July 20, 2025, 5:08pm UTC](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385/31 "2025-07-20T17:08:50Z")

</div>



[Previous page](https://discuss.python.org/t/pre-pep-include-pylock-toml-files-inside-wheels/99385.md?page=1)
