It seems like the main problem is what to do about dynamic sdist installs. An option used by some tools now is to observe what is installed and lock that. Those tools are making a tradeoff that they aren’t guaranteed to be reproducible with other platform markers. Another tool could make the opposite call and error in that case.
We could add a way to manually record “this package is an sdist that might install any of this set of packages”. Instead of recording the exact set of dependencies (with platform markers) for a wheel, the tool generating the lock file records the possible dependencies for the sdist as specified manually by the user. Then the tool installing from the lock file sees that the package is an sdist, lets it run to figure out what packages it actually wants to install, then installs those from the lock file.
# pyproject.toml
[project]
dependencies = ["regular-wheel", "complex-sdist", "basic-sdist"]
# a new section used by lock tools
[[lock.dynamic-sdist]]
name = "complex-sdist"
possible-dependencies = [
"library>=5",
"library<5",
"windows-only",
]
If lock.dynamic-sdists
isn’t defined for a given sdist, a tool can decide to do what tools do now and lock what ends up installed, or show an error. The error message could be helpful, or could just be a warning that assumptions were made:
Can’t lock “complex-sdist” because it doesn’t have wheels available. See the docs for how to specify its possible dependencies for locking. On this platform, I observed that it installed “library==5.0.3” and “windows-only==1.1”.
Can’t guarantee that all possible dependencies for “complex-sdist” were locked because it doesn’t have wheels available. See the docs for how to specify its possible dependencies if needed.
Yes, it would require some extra work on the user at that point to determine what to actually write in as the dependencies. That could be an incentive to report that to projects and either have them release wheels, or otherwise document what their possible dependencies are if they have to be an sdist.
The lock file might end up looking like this. I’m just going off what pdm.lock
looks like.
[[package]]
name = "my-app"
version = "1.0"
type = "wheel"
dependencies = ["regular-wheel==2.0.1", "complex-sdist==1.4", "basic-sdist==1.3"]
[[package]]
name = "regular-wheel"
version = "2.0.1"
type = "wheel"
dependencies = ["numpy==1.23.3"]
[[package]]
name = "complex-sdist"
version = "1.4"
type = "sdist"
possible-dependencies = ["library==5.0.3", "library==4.8.1", "windows-only=1.1"]
[[package]]
name = "basic-sdist"
version = "1.3"
type = "sdist"
possible-dependencies = []
# and then the pins for the dependencies/possibles as well
# and the file names and hashes
The tool has recorded what type of thing it is locking, which is not done today. When installing, if a tool sees wheel
it can just follow each dependency and install it as usual. If it sees sdist
it can run the sdist but only install from packages that match what’s in the lock file.