What Does the Python Version Number x.y Actually Mean?
At work, we use uv to manage Python projects, which allows us to quickly install
dependencies and lock sub-dependency versions. After returning from a period of
leave, I routinely updated the packages on my computer and noticed that uv had a
new version, so I updated it. However, after updating the uv.lock
file in a
project, I found that many wheels for dependencies had disappeared from the lock
file.
For example, here’s the configuration of the pyproject.toml
file:
[project]
name = "demo"
version = "0.1.0"
readme = "README.md"
dependencies = [
"pymongo==4.10.0",
]
requires-python = "==3.12"
After upgrading the pymongo version in the new release, the wheels disappeared:
[[package]]
name = "pymongo"
-version = "4.8.0"
+version = "4.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "dnspython" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/05/2c/ad0896cb94668c3cad1eb702ab60ae17036b051f54cfe547f11a0322f1d3/pymongo-4.8.0.tar.gz", hash = "sha256:454f2295875744dc70f1881e4b2eb99cdad008a33574bc8aaf120530f66c0cde", size = 1506091 }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/9e/8d/b082d026f96215a76553032620549f931679da7f941018e2c358fd549faa/pymongo-4.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e6a720a3d22b54183352dc65f08cd1547204d263e0651b213a0a2e577e838526", size = 699090 },
- { url = "https://files.pythonhosted.org/packages/eb/da/fa51bb7d8d5c8b4672b72c05a9357b5f9300f48128574c746fa4825f607a/pymongo-4.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:31e4d21201bdf15064cf47ce7b74722d3e1aea2597c6785882244a3bb58c7eab", size = 698800 },
- { url = "https://files.pythonhosted.org/packages/7b/dc/78f0c931d38bece6ae1dc49035961c82f3eb42952c745391ebdd3a910222/pymongo-4.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6b804bb4f2d9dc389cc9e827d579fa327272cdb0629a99bfe5b83cb3e269ebf", size = 1655527 },
- { url = "https://files.pythonhosted.org/packages/74/36/92f0eeeb5111c332072e37efb1d5a668c5e4b75be53cbd06a77f6b4192d2/pymongo-4.8.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2fbdb87fe5075c8beb17a5c16348a1ea3c8b282a5cb72d173330be2fecf22f5", size = 1718203 },
- { url = "https://files.pythonhosted.org/packages/98/40/757579f837dadaddf167cd36ae85a7ab29c035bc0ae8d90bdc8a5fbdfc33/pymongo-4.8.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd39455b7ee70aabee46f7399b32ab38b86b236c069ae559e22be6b46b2bbfc4", size = 1685776 },
- { url = "https://files.pythonhosted.org/packages/24/bb/13d23966ad01511610a471eae480bcb6a94b832c40f2bdbc706f7a757b76/pymongo-4.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940d456774b17814bac5ea7fc28188c7a1338d4a233efbb6ba01de957bded2e8", size = 1650569 },
- { url = "https://files.pythonhosted.org/packages/b5/80/1f405ce80cb6a3867709147e24a2f69e342ff71fb1b9ba663d0237f0c5ed/pymongo-4.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:236bbd7d0aef62e64caf4b24ca200f8c8670d1a6f5ea828c39eccdae423bc2b2", size = 1601592 },
- { url = "https://files.pythonhosted.org/packages/30/19/cd66230b6407c6b8cf45c1ae073659a88af5699c792c46fd4eaf317bd11e/pymongo-4.8.0-cp312-cp312-win32.whl", hash = "sha256:47ec8c3f0a7b2212dbc9be08d3bf17bc89abd211901093e3ef3f2adea7de7a69", size = 656042 },
- { url = "https://files.pythonhosted.org/packages/99/1c/f5108dc39450077556844abfd92b768c57775f85270fc0b1dc834ad18113/pymongo-4.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e84bc7707492f06fbc37a9f215374d2977d21b72e10a67f1b31893ec5a140ad8", size = 680400 },
-]
+sdist = { url = "https://files.pythonhosted.org/packages/31/8a/324251afdeab2ea5ff94dc84b8d310b389edfaa49074f677d74833e06d03/pymongo-4.10.0.tar.gz", hash = "sha256:2b56e499e0066c4a21a26b451b10377f147c360aa318f49f8c640b7f588e8e8c", size = 1896136 }
I found the related PR from a recent uv release,
astral-sh/uv#7904
, which
simplifies the size of the uv.lock
file by automatically ignoring wheels that
are irrelevant to the required Python version. This seems reasonable, but it’s
only from this version onward. So, I filed an issue:
astral-sh/uv#8169
.
After communicating with the project maintainers, I learned that the Python version number x.y is actually shorthand for x.y.0. This behavior is defined in Version specifiers, but I hadn’t noticed this detail before. In fact, the original text in L224-L227 explicitly states:
``X.Y`` and ``X.Y.0`` are not considered distinct release numbers, as
the release segment comparison rules implicit expand the two component
form to ``X.Y.0`` when comparing it to any release segment that includes
three components.
So the correct way to write it is requires-python = "==3.12.*"
.