Pre-PEP: Locking a PEP 723 single-file script

Thanks for the response.

Great if we agree already! My initial response had been to “I’ll object strongly to any attempt to remove that flexibility”. I think it’s fine to keep flexibility, in the sense of not constraining reasonable usage patterns without any rationale. But for the /// lock sections, there is a clear rationale to curtail that flexibility somewhat, in the sense that “hiding” executable in/after large comments does not become an attack vector.

So I think we agree that flexibility is good (e.g. introducing other types of blocks can be introduced as necessary). We may also agree that if lockfiles get added to scripts, they should be at the end.

Unusually for me in these discussions, I have a very concrete memory of (and to some degree, participation in) this; to me the distinguishing factor in favour of PEP 723 was hewing as closely as possible to the established pyproject.toml style of dependency-specification, rather than inventing another scheme to do so. The former naturally includes a degree of flexibility – tools can leverage existing patterns to add something like

# [tool.uv]
# exclude-newer = "2023-01-10T00:00:00Z"

and no spec or implementation needs to be changed for this to make sense or be compatible –, but that doesn’t mean that flexibility in and of itself was the overriding principle.

I think the key point is avoiding executable code creeping in after large lockfile blocks. Anything that’s just comments could still be allowed. I guess I could live with a “strong recommendation”, though preferably my suggestion would be: “your locked script is the concatenation of foo.py plus its lockfile”.

That might actually be a neat approach to square the circle with the whole sidecar discussion. In that way, users could choose if they want to have

foo.py       # unchanged
foo.py.lock  # sidecar
# or
foo.py  # concatenation of original + its lockfile (wrapped into `/// lock` block)

and both variants would be trivially transformable into the other. Normally we prefer “one and only one way to do it”, but as long as the two instances are kept interconvertible[1], this wouldn’t actually be a large implementation burden IMO, but would provide users with a meaningful choice that’s hard to dictate for everyone (i.e. whether keeping everything in one file is more important, or whether they want to avoid large blobs in their scripts).


  1. something that would clearly favour keeping the /// lock section at the end to simplify this process ↩︎