Skip to content

Commit

Permalink
Merge pull request #11217 from uranusjr/importlib-metadata-ignore-dis…
Browse files Browse the repository at this point in the history
…t-info-in-wheel
  • Loading branch information
uranusjr authored Jul 1, 2022
2 parents 06f79b8 + 6eaa8e9 commit c260ecc
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 0 deletions.
4 changes: 4 additions & 0 deletions news/11217.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Do not consider a ``.dist-info`` directory found inside a wheel-like zip file
as metadata for an installed distribution. A package in a wheel is (by
definition) not installed, and is not guaranteed to work due to how a wheel is
structured.
17 changes: 17 additions & 0 deletions src/pip/_internal/metadata/importlib/_envs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,24 @@
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name

from pip._internal.metadata.base import BaseDistribution, BaseEnvironment
from pip._internal.models.wheel import Wheel
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.filetypes import WHEEL_EXTENSION

from ._compat import BasePath, get_dist_name, get_info_location
from ._dists import Distribution


def _looks_like_wheel(location: str) -> bool:
if not location.endswith(WHEEL_EXTENSION):
return False
if not os.path.isfile(location):
return False
if not Wheel.wheel_file_re.match(os.path.basename(location)):
return False
return zipfile.is_zipfile(location)


class _DistributionFinder:
"""Finder to locate distributions.
Expand All @@ -36,6 +48,11 @@ def __init__(self) -> None:

def _find_impl(self, location: str) -> Iterator[FoundResult]:
"""Find distributions in a location."""
# Skip looking inside a wheel. Since a package inside a wheel is not
# always valid (due to .data directories etc.), its .dist-info entry
# should not be considered an installed distribution.
if _looks_like_wheel(location):
return
# To know exactly where we find a distribution, we have to feed in the
# paths one by one, instead of dumping the list to importlib.metadata.
for dist in importlib.metadata.distributions(path=[location]):
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/metadata/test_metadata.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import os
from pathlib import Path
from typing import cast
from unittest import mock
Expand All @@ -9,6 +10,7 @@
from pip._internal.metadata import (
BaseDistribution,
get_directory_distribution,
get_environment,
get_wheel_distribution,
)
from pip._internal.metadata.base import FilesystemWheel
Expand Down Expand Up @@ -102,3 +104,28 @@ def test_metadata_dict(tmp_path: Path) -> None:
metadata_dict = dist.metadata_dict
assert metadata_dict["name"] == "pkga"
assert metadata_dict["version"] == "1.0.1"


def test_no_dist_found_in_wheel(tmp_path: Path) -> None:
location = os.fspath(tmp_path.joinpath("pkg-1-py3-none-any.whl"))
make_wheel(name="pkg", version="1").save_to(location)
assert get_environment([location]).get_distribution("pkg") is None


def test_dist_found_in_directory_named_whl(tmp_path: Path) -> None:
dir_path = tmp_path.joinpath("pkg-1-py3-none-any.whl")
info_path = dir_path.joinpath("pkg-1.dist-info")
info_path.mkdir(parents=True)
info_path.joinpath("METADATA").write_text("Name: pkg")
location = os.fspath(dir_path)
dist = get_environment([location]).get_distribution("pkg")
assert dist is not None and dist.location is not None
assert Path(dist.location) == Path(location)


def test_dist_found_in_zip(tmp_path: Path) -> None:
location = os.fspath(tmp_path.joinpath("pkg.zip"))
make_wheel(name="pkg", version="1").save_to(location)
dist = get_environment([location]).get_distribution("pkg")
assert dist is not None and dist.location is not None
assert Path(dist.location) == Path(location)

0 comments on commit c260ecc

Please sign in to comment.