Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip invalid versions on PyPI #54

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## [0.2.2] - 2023/03/04

### Fixed

- When there is an invalid version on PyPi (defined as unparsable
by [`packaging.version.Version`](https://packaging.pypa.io/en/stable/version.html))
that version is now skipped. Otherwise a single invalid version would
make the package uninstallable, following removal of `LegacyVersion` in
[packaging#407](https://github.com/pypa/packaging/pull/407).

### Fixed

## [0.2.1] - 2023/02/20

### Changed
Expand Down
14 changes: 12 additions & 2 deletions micropip/_micropip.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from packaging.requirements import Requirement
from packaging.tags import Tag, sys_tags
from packaging.utils import canonicalize_name, parse_wheel_filename
from packaging.version import Version
from packaging.version import InvalidVersion, Version

from . import _mock_package
from ._compat import (
Expand Down Expand Up @@ -268,7 +268,17 @@ def find_wheel(metadata: dict[str, Any], req: Requirement) -> WheelInfo:
ver : Version or None
The version of the Python wheel, or None if there is no pure Python wheel.
"""
releases = metadata.get("releases", {})
releases_raw = metadata.get("releases", {})
releases = {}
# Skip unparsable versions
for key, val in releases_raw.items():
try:
Version(key)
except InvalidVersion:
continue

releases[key] = val

candidate_versions = sorted(
(Version(v) for v in req.specifier.filter(releases)),
reverse=True,
Expand Down
21 changes: 21 additions & 0 deletions tests/test_micropip.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,27 @@ def test_last_version_from_pypi():
assert str(wheel.version) == "0.15.5"


def test_find_wheel_invalid_version():
"""Check that if the one version on PyPi is unparsable

it should be skipped instead of producing an error
"""
pytest.importorskip("packaging")
from packaging.requirements import Requirement

from micropip._micropip import find_wheel

requirement = Requirement("dummy_module")
versions = ["0.0.1", "0.15.5", "0.9.1", "2004d"]

metadata = _pypi_metadata("dummy_module", {v: ["py3"] for v in versions})

# get version number from find_wheel
wheel = find_wheel(metadata, requirement)

assert str(wheel.version) == "0.15.5"


_best_tag_test_cases = (
"package, version, incompatible_tags, compatible_tags",
# Tests assume that `compatible_tags` is sorted from least to most compatible:
Expand Down