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

Update pip and pip-tools to latest versions #4215

Merged
merged 13 commits into from
Apr 28, 2020
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/4215.vendor.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Updated vendored ``pip`` => ``20.0.2`` and ``pip-tools`` => ``5.0.0``.
19 changes: 18 additions & 1 deletion pipenv/patched/notpip/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
__version__ = "19.3.1"
from pipenv.patched.notpip._internal.utils.typing import MYPY_CHECK_RUNNING

if MYPY_CHECK_RUNNING:
from typing import List, Optional


__version__ = "20.0.2"


def main(args=None):
# type: (Optional[List[str]]) -> int
"""This is an internal API only meant for use by pip's own console scripts.

For additional details, see https://github.com/pypa/pip/issues/7498.
"""
from pipenv.patched.notpip._internal.utils.entrypoints import _wrapper

return _wrapper(args)
2 changes: 1 addition & 1 deletion pipenv/patched/notpip/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
path = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, path)

from pipenv.patched.notpip._internal.main import main as _main # isort:skip # noqa
from pipenv.patched.notpip._internal.cli.main import main as _main # isort:skip # noqa

if __name__ == '__main__':
sys.exit(_main())
16 changes: 16 additions & 0 deletions pipenv/patched/notpip/_internal/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
#!/usr/bin/env python
import pipenv.patched.notpip._internal.utils.inject_securetransport # noqa
from pipenv.patched.notpip._internal.utils.typing import MYPY_CHECK_RUNNING

if MYPY_CHECK_RUNNING:
from typing import Optional, List


def main(args=None):
# type: (Optional[List[str]]) -> int
"""This is preserved for old console scripts that may still be referencing
it.

For additional details, see https://github.com/pypa/pip/issues/7498.
"""
from pipenv.patched.notpip._internal.utils.entrypoints import _wrapper

return _wrapper(args)
2 changes: 1 addition & 1 deletion pipenv/patched/notpip/_internal/build_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

if MYPY_CHECK_RUNNING:
from typing import Tuple, Set, Iterable, Optional, List
from pipenv.patched.notpip._internal.index import PackageFinder
from pipenv.patched.notpip._internal.index.package_finder import PackageFinder

logger = logging.getLogger(__name__)

Expand Down
140 changes: 108 additions & 32 deletions pipenv/patched/notpip/_internal/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,38 @@
# The following comment should be removed at some point in the future.
# mypy: strict-optional=False

import errno
import hashlib
import json
import logging
import os

from pipenv.patched.notpip._vendor.packaging.tags import interpreter_name, interpreter_version
from pipenv.patched.notpip._vendor.packaging.utils import canonicalize_name

from pipenv.patched.notpip._internal.exceptions import InvalidWheelFilename
from pipenv.patched.notpip._internal.models.link import Link
from pipenv.patched.notpip._internal.utils.compat import expanduser
from pipenv.patched.notpip._internal.models.wheel import Wheel
from pipenv.patched.notpip._internal.utils.temp_dir import TempDirectory
from pipenv.patched.notpip._internal.utils.typing import MYPY_CHECK_RUNNING
from pipenv.patched.notpip._internal.utils.urls import path_to_url
from pipenv.patched.notpip._internal.wheel import InvalidWheelFilename, Wheel

if MYPY_CHECK_RUNNING:
from typing import Optional, Set, List, Any
from pipenv.patched.notpip._internal.index import FormatControl
from pipenv.patched.notpip._internal.pep425tags import Pep425Tag
from typing import Optional, Set, List, Any, Dict

from pipenv.patched.notpip._vendor.packaging.tags import Tag

from pipenv.patched.notpip._internal.models.format_control import FormatControl

logger = logging.getLogger(__name__)


def _hash_dict(d):
# type: (Dict[str, str]) -> str
"""Return a stable sha224 of a dictionary."""
s = json.dumps(d, sort_keys=True, separators=(",", ":"), ensure_ascii=True)
return hashlib.sha224(s.encode("ascii")).hexdigest()


class Cache(object):
"""An abstract class - provides cache directories for data from links

Expand All @@ -40,16 +50,19 @@ class Cache(object):
def __init__(self, cache_dir, format_control, allowed_formats):
# type: (str, FormatControl, Set[str]) -> None
super(Cache, self).__init__()
self.cache_dir = expanduser(cache_dir) if cache_dir else None
assert not cache_dir or os.path.isabs(cache_dir)
self.cache_dir = cache_dir or None
self.format_control = format_control
self.allowed_formats = allowed_formats

_valid_formats = {"source", "binary"}
assert self.allowed_formats.union(_valid_formats) == _valid_formats

def _get_cache_path_parts(self, link):
def _get_cache_path_parts_legacy(self, link):
# type: (Link) -> List[str]
"""Get parts of part that must be os.path.joined with cache_dir

Legacy cache key (pip < 20) for compatibility with older caches.
"""

# We want to generate an url to use as our cache key, we don't want to
Expand All @@ -73,30 +86,72 @@ def _get_cache_path_parts(self, link):

return parts

def _get_candidates(self, link, package_name):
def _get_cache_path_parts(self, link):
# type: (Link) -> List[str]
"""Get parts of part that must be os.path.joined with cache_dir
"""

# We want to generate an url to use as our cache key, we don't want to
# just re-use the URL because it might have other items in the fragment
# and we don't care about those.
key_parts = {"url": link.url_without_fragment}
if link.hash_name is not None and link.hash is not None:
key_parts[link.hash_name] = link.hash
if link.subdirectory_fragment:
key_parts["subdirectory"] = link.subdirectory_fragment

# Include interpreter name, major and minor version in cache key
# to cope with ill-behaved sdists that build a different wheel
# depending on the python version their setup.py is being run on,
# and don't encode the difference in compatibility tags.
# https://github.com/pypa/pip/issues/7296
key_parts["interpreter_name"] = interpreter_name()
key_parts["interpreter_version"] = interpreter_version()

# Encode our key url with sha224, we'll use this because it has similar
# security properties to sha256, but with a shorter total output (and
# thus less secure). However the differences don't make a lot of
# difference for our use case here.
hashed = _hash_dict(key_parts)

# We want to nest the directories some to prevent having a ton of top
# level directories where we might run out of sub directories on some
# FS.
parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]]

return parts

def _get_candidates(self, link, canonical_package_name):
# type: (Link, Optional[str]) -> List[Any]
can_not_cache = (
not self.cache_dir or
not package_name or
not canonical_package_name or
not link
)
if can_not_cache:
return []

canonical_name = canonicalize_name(package_name)
formats = self.format_control.get_allowed_formats(
canonical_name
canonical_package_name
)
if not self.allowed_formats.intersection(formats):
return []

root = self.get_path_for_link(link)
try:
return os.listdir(root)
except OSError as err:
if err.errno in {errno.ENOENT, errno.ENOTDIR}:
return []
raise
candidates = []
path = self.get_path_for_link(link)
if os.path.isdir(path):
for candidate in os.listdir(path):
candidates.append((candidate, path))
# TODO remove legacy path lookup in pip>=21
legacy_path = self.get_path_for_link_legacy(link)
if os.path.isdir(legacy_path):
for candidate in os.listdir(legacy_path):
candidates.append((candidate, legacy_path))
return candidates

def get_path_for_link_legacy(self, link):
# type: (Link) -> str
raise NotImplementedError()

def get_path_for_link(self, link):
# type: (Link) -> str
Expand All @@ -108,21 +163,14 @@ def get(
self,
link, # type: Link
package_name, # type: Optional[str]
supported_tags, # type: List[Pep425Tag]
supported_tags, # type: List[Tag]
):
# type: (...) -> Link
"""Returns a link to a cached item if it exists, otherwise returns the
passed link.
"""
raise NotImplementedError()

def _link_for_candidate(self, link, candidate):
# type: (Link, str) -> Link
root = self.get_path_for_link(link)
path = os.path.join(root, candidate)

return Link(path_to_url(path))

def cleanup(self):
# type: () -> None
pass
Expand All @@ -138,6 +186,11 @@ def __init__(self, cache_dir, format_control):
cache_dir, format_control, {"binary"}
)

def get_path_for_link_legacy(self, link):
# type: (Link) -> str
parts = self._get_cache_path_parts_legacy(link)
return os.path.join(self.cache_dir, "wheels", *parts)

def get_path_for_link(self, link):
# type: (Link) -> str
"""Return a directory to store cached wheels for link
Expand All @@ -163,27 +216,46 @@ def get(
self,
link, # type: Link
package_name, # type: Optional[str]
supported_tags, # type: List[Pep425Tag]
supported_tags, # type: List[Tag]
):
# type: (...) -> Link
candidates = []

for wheel_name in self._get_candidates(link, package_name):
if not package_name:
return link

canonical_package_name = canonicalize_name(package_name)
for wheel_name, wheel_dir in self._get_candidates(
link, canonical_package_name
):
try:
wheel = Wheel(wheel_name)
except InvalidWheelFilename:
continue
if canonicalize_name(wheel.name) != canonical_package_name:
logger.debug(
"Ignoring cached wheel {} for {} as it "
"does not match the expected distribution name {}.".format(
wheel_name, link, package_name
)
)
continue
if not wheel.supported(supported_tags):
# Built for a different python/arch/etc
continue
candidates.append(
(wheel.support_index_min(supported_tags), wheel_name)
(
wheel.support_index_min(supported_tags),
wheel_name,
wheel_dir,
)
)

if not candidates:
return link

return self._link_for_candidate(link, min(candidates)[1])
_, wheel_name, wheel_dir = min(candidates)
return Link(path_to_url(os.path.join(wheel_dir, wheel_name)))


class EphemWheelCache(SimpleWheelCache):
Expand Down Expand Up @@ -218,6 +290,10 @@ def __init__(self, cache_dir, format_control):
self._wheel_cache = SimpleWheelCache(cache_dir, format_control)
self._ephem_cache = EphemWheelCache(format_control)

def get_path_for_link_legacy(self, link):
# type: (Link) -> str
return self._wheel_cache.get_path_for_link_legacy(link)

def get_path_for_link(self, link):
# type: (Link) -> str
return self._wheel_cache.get_path_for_link(link)
Expand All @@ -230,7 +306,7 @@ def get(
self,
link, # type: Link
package_name, # type: Optional[str]
supported_tags, # type: List[Pep425Tag]
supported_tags, # type: List[Tag]
):
# type: (...) -> Link
retval = self._wheel_cache.get(
Expand Down
Loading