mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
Don't consider dist-info in a wheel as "installed"
This applies to the new importlib.metadata backend. The legacy pkg_resources backend already does this (albeit accidentally). A package inside a wheel is not guaranteed to "work" when directly imported, so we should not treat it as an installed distribution.
This commit is contained in:
parent
06f79b8ee6
commit
6eaa8e9135
4
news/11217.bugfix.rst
Normal file
4
news/11217.bugfix.rst
Normal file
|
@ -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.
|
|
@ -10,12 +10,24 @@ from typing import Iterator, List, Optional, Sequence, Set, Tuple
|
|||
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.
|
||||
|
||||
|
@ -36,6 +48,11 @@ class _DistributionFinder:
|
|||
|
||||
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]):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import cast
|
||||
from unittest import mock
|
||||
|
@ -9,6 +10,7 @@ from pip._vendor.packaging.utils import NormalizedName
|
|||
from pip._internal.metadata import (
|
||||
BaseDistribution,
|
||||
get_directory_distribution,
|
||||
get_environment,
|
||||
get_wheel_distribution,
|
||||
)
|
||||
from pip._internal.metadata.base import FilesystemWheel
|
||||
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue