Of course, all of these either have flaws [1] or are so detailed that they're distributed build caches with more steps. You can hash project source files, all build commands, all textually included headers, precise versions of toolchains, etc., into a Merkle tree, but this is not generally how python applications pin "versions" of dependencies.
[1] For instance, you cannot version a C or C++ library build independent from the versions of all of the transitive dependencies of that library (more or less). Of the options listed here, only distribution package managers can really account for this problem, and not every distribution package manager cares to.