Skip to content

Commit 8ba6b75

Browse files
committed
Better workaround for cache poisoning #3025
Make sure ``pip wheel`` never outputs pure python wheels with a python implementation tag. Better fix/workaround for `#3025 <https://github.com/pypa/pip/issues/3025>`_ by using a per-implementation wheel cache instead of caching pure python wheels with an implementation tag in their name. Fixes #7296
1 parent 2ed5d56 commit 8ba6b75

File tree

5 files changed

+34
-13
lines changed

5 files changed

+34
-13
lines changed

news/7296.bugfix

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Make sure ``pip wheel`` never outputs pure python wheels with a
2+
python implementation tag. Better fix/workaround for
3+
`#3025 <https://github.com/pypa/pip/issues/3025>`_ by
4+
using a per-implementation wheel cache instead of caching pure python
5+
wheels with an implementation tag in their name.

src/pip/_internal/cache.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
import hashlib
99
import logging
1010
import os
11+
import sys
1112

1213
from pip._vendor.packaging.utils import canonicalize_name
1314

1415
from pip._internal.models.link import Link
1516
from pip._internal.utils.compat import expanduser
17+
from pip._internal.utils.misc import interpreter_name
1618
from pip._internal.utils.temp_dir import TempDirectory
1719
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
1820
from pip._internal.utils.urls import path_to_url
@@ -60,11 +62,23 @@ def _get_cache_path_parts(self, link):
6062
key_parts.append("=".join([link.hash_name, link.hash]))
6163
key_url = "#".join(key_parts)
6264

65+
# Include interpreter name, major and minor version in cache key
66+
# to cope with ill-behaved sdists that build a different wheel
67+
# depending on the python version their setup.py is being run on,
68+
# and don't encode the difference in compatibility tags.
69+
# https://github.com/pypa/pip/issues/7296
70+
key = "{}-{}.{} {}".format(
71+
interpreter_name(),
72+
sys.version_info[0],
73+
sys.version_info[1],
74+
key_url,
75+
)
76+
6377
# Encode our key url with sha224, we'll use this because it has similar
6478
# security properties to sha256, but with a shorter total output (and
6579
# thus less secure). However the differences don't make a lot of
6680
# difference for our use case here.
67-
hashed = hashlib.sha224(key_url.encode()).hexdigest()
81+
hashed = hashlib.sha224(key.encode()).hexdigest()
6882

6983
# We want to nest the directories some to prevent having a ton of top
7084
# level directories where we might run out of sub directories on some

src/pip/_internal/utils/misc.py

+11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io
1212
import logging
1313
import os
14+
import platform
1415
import posixpath
1516
import shutil
1617
import stat
@@ -878,3 +879,13 @@ def hash_file(path, blocksize=1 << 20):
878879
length += len(block)
879880
h.update(block)
880881
return (h, length) # type: ignore
882+
883+
884+
def interpreter_name():
885+
# type: () -> str
886+
try:
887+
name = sys.implementation.name # type: ignore
888+
except AttributeError: # pragma: no cover
889+
# Python 2.7 compatibility.
890+
name = platform.python_implementation().lower()
891+
return name

src/pip/_internal/wheel_builder.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import re
1010
import shutil
1111

12-
from pip._internal import pep425tags
1312
from pip._internal.models.link import Link
1413
from pip._internal.utils.logging import indent_log
1514
from pip._internal.utils.marker_files import has_delete_marker_file
@@ -447,10 +446,6 @@ def build(
447446
', '.join([req.name for (req, _) in buildset]),
448447
)
449448

450-
python_tag = None
451-
if should_unpack:
452-
python_tag = pep425tags.implementation_tag
453-
454449
with indent_log():
455450
build_success, build_failure = [], []
456451
for req, output_dir in buildset:
@@ -464,10 +459,7 @@ def build(
464459
build_failure.append(req)
465460
continue
466461

467-
wheel_file = self._build_one(
468-
req, output_dir,
469-
python_tag=python_tag,
470-
)
462+
wheel_file = self._build_one(req, output_dir)
471463
if wheel_file:
472464
if should_unpack:
473465
# XXX: This is mildly duplicative with prepare_files,

tests/functional/test_install.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from pip._vendor.six import PY2
1313

1414
from pip import __version__ as pip_current_version
15-
from pip._internal import pep425tags
1615
from pip._internal.cli.status_codes import ERROR, SUCCESS
1716
from pip._internal.models.index import PyPI, TestPyPI
1817
from pip._internal.utils.misc import rmtree
@@ -1297,9 +1296,9 @@ def test_install_builds_wheels(script, data, with_wheel):
12971296
assert "Running setup.py install for requir" not in str(res), str(res)
12981297
# wheelbroken has to run install
12991298
assert "Running setup.py install for wheelb" in str(res), str(res)
1300-
# We want to make sure we used the correct implementation tag
1299+
# We want to make sure pure python wheels do not have an implementation tag
13011300
assert wheels == [
1302-
"Upper-2.0-{}-none-any.whl".format(pep425tags.implementation_tag),
1301+
"Upper-2.0-py{}-none-any.whl".format(sys.version_info[0]),
13031302
]
13041303

13051304

0 commit comments

Comments
 (0)