diff --git a/CHANGELOG.md b/CHANGELOG.md index ae3a7d5..bbab7af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/micropip/_micropip.py b/micropip/_micropip.py index 7b25385..176cf6f 100644 --- a/micropip/_micropip.py +++ b/micropip/_micropip.py @@ -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 ( @@ -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, diff --git a/tests/test_micropip.py b/tests/test_micropip.py index 362e6eb..149c4db 100644 --- a/tests/test_micropip.py +++ b/tests/test_micropip.py @@ -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: