-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Use lazy wheel to obtain dep info for new resolver #8532
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
Changes from all commits
a073856
d718192
c127459
4db613c
c53aeac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Allow the new resolver to obtain dependency information through wheels | ||
lazily downloaded using HTTP range requests. To enable this feature, | ||
invoke ``pip`` with ``--use-feature=fast-deps``. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -271,6 +271,7 @@ def make_resolver( | |
force_reinstall=force_reinstall, | ||
upgrade_strategy=upgrade_strategy, | ||
py_version_info=py_version_info, | ||
lazy_wheel='fast-deps' in options.features_enabled, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oooo! I missed I think we can cover this by changing how self.dist is populated (instead of changing how iter_dependencies works), since what's really happening in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to what was done in #8448. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pradyunsg, I think we did discuss point (5) and what you came up with (1a28d08) will handle it just fine. So now we came to a consensus on how to cover the listed points above, which is different from what this PR is pushing, I'm thinking about filing another one (likely within today) to avoid intensive rebasing which I'm not exactly good at 😄 @chrahunt, thank you for the thoughtful heads up as well as the tips on testing. |
||
) | ||
import pip._internal.resolution.legacy.resolver | ||
return pip._internal.resolution.legacy.resolver.Resolver( | ||
|
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 | ||||||
|
@@ -23,13 +23,18 @@ | |||||
from pip._internal.network.session import PipSession | ||||||
|
||||||
|
||||||
class HTTPRangeRequestUnsupported(RuntimeError): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
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, | ||||||
|
@@ -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): | ||||||
|
@@ -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 | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are any of these tests exercising the new code? It will only impact the network tests, and there aren't many in our unit tests. Personally I'd trade all of these for 1 or 2 integration tests where we know the new code is being used. werkzeug (which we build on for our mock server test helper) has some built-in helpers for handling range requests so we could do all of this locally, without reaching out to PyPI. The PR in pallets/werkzeug#977 might provide some help in using it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To add on to this, because of the code that we're touching, these are the specific integration tests I think would give us the most impact:
pip wheel
pip download
pip install
of a wheel that has extras that are also wheelsOne approach would be to find existing integration tests, then convert them to use our mock server and then parameterize which mock server to use: plain one or range-request-supporting one.