fix: treat bare version constraints as exact match
When resolving dependencies like certifi@2025.10.5, the bare version string "2025.10.5" was being rejected as an invalid SpecifierSet and falling back to wildcard, which fetched the latest version instead. Now bare versions starting with a digit are automatically prefixed with "==" to create an exact match constraint.
This commit is contained in:
@@ -269,8 +269,18 @@ class PyPIRegistryClient(RegistryClient):
|
||||
return None
|
||||
|
||||
# Parse constraint
|
||||
# If constraint looks like a bare version (no operator), treat as exact match
|
||||
# e.g., "2025.10.5" -> "==2025.10.5"
|
||||
effective_constraint = constraint
|
||||
if constraint and constraint[0].isdigit():
|
||||
effective_constraint = f"=={constraint}"
|
||||
logger.debug(
|
||||
f"Bare version '{constraint}' for {normalized}, "
|
||||
f"treating as exact match '{effective_constraint}'"
|
||||
)
|
||||
|
||||
try:
|
||||
specifier = SpecifierSet(constraint)
|
||||
specifier = SpecifierSet(effective_constraint)
|
||||
except InvalidSpecifier:
|
||||
# Invalid constraint - treat as wildcard
|
||||
logger.warning(
|
||||
|
||||
@@ -176,6 +176,42 @@ class TestPyPIRegistryClient:
|
||||
|
||||
assert result is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_resolve_constraint_bare_version(self, client, mock_http_client):
|
||||
"""Test resolving bare version string as exact match."""
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"info": {"version": "2.0.0"},
|
||||
"releases": {
|
||||
"1.0.0": [
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"url": "https://files.pythonhosted.org/test-1.0.0.whl",
|
||||
"filename": "test-1.0.0.whl",
|
||||
"digests": {"sha256": "abc123"},
|
||||
"size": 1000,
|
||||
}
|
||||
],
|
||||
"2.0.0": [
|
||||
{
|
||||
"packagetype": "bdist_wheel",
|
||||
"url": "https://files.pythonhosted.org/test-2.0.0.whl",
|
||||
"filename": "test-2.0.0.whl",
|
||||
"digests": {"sha256": "def456"},
|
||||
"size": 2000,
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
mock_http_client.get.return_value = mock_response
|
||||
|
||||
# Bare version "1.0.0" should resolve to exactly 1.0.0, not latest
|
||||
result = await client.resolve_constraint("test-package", "1.0.0")
|
||||
|
||||
assert result is not None
|
||||
assert result.version == "1.0.0"
|
||||
|
||||
|
||||
class TestVersionInfo:
|
||||
"""Tests for VersionInfo dataclass."""
|
||||
|
||||
Reference in New Issue
Block a user