Skip to content

Commit

Permalink
Use more descriptive exception when range requests are unsupported
Browse files Browse the repository at this point in the history
  • Loading branch information
McSinyx committed Jul 6, 2020
1 parent 0872339 commit ad5d3dc
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 11 deletions.
14 changes: 10 additions & 4 deletions src/pip/_internal/network/lazy_wheel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Lazy ZIP over HTTP"""

__all__ = ['dist_from_wheel_url']
__all__ = ['HTTPRangeRequestUnsupported', 'dist_from_wheel_url']

from bisect import bisect_left, bisect_right
from contextlib import contextmanager
Expand All @@ -23,13 +23,18 @@
from pip._internal.network.session import PipSession


class HTTPRangeRequestUnsupported(RuntimeError):
pass


def dist_from_wheel_url(name, url, session):
# type: (str, str, PipSession) -> Distribution
"""Return a pkg_resources.Distribution from the given wheel URL.
This uses HTTP range requests to only fetch the potion of the wheel
containing metadata, just enough for the object to be constructed.
If such requests are not supported, RuntimeError is raised.
If such requests are not supported, HTTPRangeRequestUnsupported
is raised.
"""
with LazyZipOverHTTP(url, session) as wheel:
# For read-only ZIP files, ZipFile only needs methods read,
Expand All @@ -45,7 +50,8 @@ class LazyZipOverHTTP(object):
This uses HTTP range requests to lazily fetch the file's content,
which is supposed to be fed to ZipFile. If such requests are not
supported by the server, raise RuntimeError during initialization.
supported by the server, raise HTTPRangeRequestUnsupported
during initialization.
"""

def __init__(self, url, session, chunk_size=CONTENT_CHUNK_SIZE):
Expand All @@ -60,7 +66,7 @@ def __init__(self, url, session, chunk_size=CONTENT_CHUNK_SIZE):
self._left = [] # type: List[int]
self._right = [] # type: List[int]
if 'bytes' not in head.headers.get('Accept-Ranges', 'none'):
raise RuntimeError('range request is not supported')
raise HTTPRangeRequestUnsupported('range request is not supported')
self._check_zip()

@property
Expand Down
19 changes: 14 additions & 5 deletions src/pip/_internal/resolution/resolvelib/candidates.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import logging
import sys

from pip._vendor.contextlib2 import suppress
from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet
from pip._vendor.packaging.utils import canonicalize_name
from pip._vendor.packaging.version import Version

from pip._internal.exceptions import HashError, MetadataInconsistent
from pip._internal.network.lazy_wheel import dist_from_wheel_url
from pip._internal.network.lazy_wheel import (
HTTPRangeRequestUnsupported,
dist_from_wheel_url,
)
from pip._internal.req.constructors import (
install_req_from_editable,
install_req_from_line,
Expand Down Expand Up @@ -308,15 +310,22 @@ def iter_dependencies(self):
assert self._name is not None
logger.info('Collecting %s', self._ireq.req or self._ireq)
# If RuntimeError is raised, fallback to self.dist.
with indent_log(), suppress(RuntimeError):
with indent_log():
logger.info(
'Obtaining dependency information from %s %s',
self._name, self._version,
)
url = self._link.url.split('#', 1)[0]
session = preparer.downloader._session
dist = dist_from_wheel_url(self._name, url, session)
self._check_metadata_consistency(dist)
try:
dist = dist_from_wheel_url(self._name, url, session)
except HTTPRangeRequestUnsupported:
logger.debug(
'Failed to get dependency information '
'using HTTP range requests from %s', url,
)
else:
self._check_metadata_consistency(dist)
return self._iter_dependencies(dist or self.dist)

def _prepare_abstract_distribution(self):
Expand Down
7 changes: 5 additions & 2 deletions tests/unit/test_network_lazy_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
from pip._vendor.pkg_resources import Requirement
from pytest import fixture, mark, raises

from pip._internal.network.lazy_wheel import dist_from_wheel_url
from pip._internal.network.lazy_wheel import (
HTTPRangeRequestUnsupported,
dist_from_wheel_url,
)
from pip._internal.network.session import PipSession
from tests.lib.requests_mocks import MockResponse

Expand Down Expand Up @@ -39,7 +42,7 @@ def test_dist_from_wheel_url(session):
def test_dist_from_wheel_url_no_range(session, monkeypatch):
"""Test handling when HTTP range requests are not supported."""
monkeypatch.setattr(session, 'head', lambda *a, **kw: MockResponse(b''))
with raises(RuntimeError):
with raises(HTTPRangeRequestUnsupported):
dist_from_wheel_url('mypy', MYPY_0_782_WHL, session)


Expand Down

0 comments on commit ad5d3dc

Please sign in to comment.