-
Notifications
You must be signed in to change notification settings - Fork 3k
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
try to build wheels for directories/vcs #4714
Changes from 21 commits
3517df5
b241c22
fa927a6
48ee5d7
b229fd4
c5297e8
8fbd8f4
e58e50f
2c67a91
ef1a3ae
a7b0e4f
58f6917
711c99a
25d5546
882c8b9
ade439c
396abfe
dd326a7
951dfdd
e168cbb
dbcd1a7
c28d614
bd31280
b6377d4
edcc6de
97c667b
43eb3c6
00281b3
02a5d58
fb09a60
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 @@ | ||
Installing from a local directory or a VCS URL now builds a wheel to install, | ||
rather than running ``setup.py install``. Wheels from these sources are not | ||
cached. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
from pip._internal.compat import expanduser | ||
from pip._internal.download import path_to_url | ||
from pip._internal.wheel import InvalidWheelFilename, Wheel | ||
from pip._internal.utils import temp_dir | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -32,6 +33,9 @@ def __init__(self, cache_dir, format_control, allowed_formats): | |
self.cache_dir = expanduser(cache_dir) if cache_dir else None | ||
self.format_control = format_control | ||
self.allowed_formats = allowed_formats | ||
# Ephemeral cache: store wheels just for this run | ||
self._ephem_cache_dir = temp_dir.TempDirectory(kind="ephem-cache") | ||
self._ephem_cache_dir.create() | ||
|
||
_valid_formats = {"source", "binary"} | ||
assert self.allowed_formats.union(_valid_formats) == _valid_formats | ||
|
@@ -102,6 +106,9 @@ def _link_for_candidate(self, link, candidate): | |
|
||
return index.Link(path_to_url(path)) | ||
|
||
def cleanup(self): | ||
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. This should be on 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. After thinking about this some more, I don't agree. I think that first of all, 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. So, specifically, I propose making this 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. Agreed. |
||
"""Remove the ephermal caches created temporarily to build wheels""" | ||
self._ephem_cache_dir.cleanup() | ||
|
||
class WheelCache(Cache): | ||
"""A cache of wheels for future installs. | ||
|
@@ -110,7 +117,7 @@ class WheelCache(Cache): | |
def __init__(self, cache_dir, format_control): | ||
super(WheelCache, self).__init__(cache_dir, format_control, {"binary"}) | ||
|
||
def get_path_for_link(self, link): | ||
def get_path_for_link(self, link, ephem=False): | ||
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. Instead of having a boolean in the signature, I'd suggest you implement a new method Relevant Blog Post: https://martinfowler.com/bliki/FlagArgument.html |
||
"""Return a directory to store cached wheels for link | ||
|
||
Because there are M wheels for any one sdist, we provide a directory | ||
|
@@ -127,9 +134,14 @@ def get_path_for_link(self, link): | |
""" | ||
parts = self._get_cache_path_parts(link) | ||
|
||
if not ephem: | ||
cache_dir = self.cache_dir | ||
else: | ||
cache_dir = self._ephem_cache_dir.path | ||
|
||
# Inside of the base location for cached wheels, expand our parts and | ||
# join them all together. | ||
return os.path.join(self.cache_dir, "wheels", *parts) | ||
return os.path.join(cache_dir, "wheels", *parts) | ||
|
||
def get(self, link, package_name): | ||
candidates = [] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,9 +16,6 @@ def __init__(self, | |
require_hashes=False, target_dir=None, use_user_site=False, | ||
pycompile=True): | ||
"""Create a RequirementSet. | ||
|
||
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. This is an unrelated (albeit obvious) change. It'd be nice if you revert this hunk and make a new PR for it. 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. 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. Uhhh, no clue, feel free to ignore whatever I did. 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. I will remove this then. |
||
:param wheel_cache: The pip wheel cache, for passing to | ||
InstallRequirement. | ||
""" | ||
|
||
self.requirements = OrderedDict() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -741,6 +741,7 @@ def build(self, session, autobuilding=False): | |
|
||
buildset = [] | ||
for req in reqset: | ||
ephem_cache = False | ||
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. bike-shedding: I'll suggest painting this as |
||
if req.constraint: | ||
continue | ||
if req.is_wheel: | ||
|
@@ -750,41 +751,42 @@ def build(self, session, autobuilding=False): | |
elif autobuilding and req.editable: | ||
pass | ||
elif autobuilding and req.link and not req.link.is_artifact: | ||
pass | ||
# VCS checkout. Build wheel just for this run. | ||
ephem_cache = True | ||
elif autobuilding and not req.source_dir: | ||
pass | ||
else: | ||
if autobuilding: | ||
link = req.link | ||
base, ext = link.splitext() | ||
if index.egg_info_matches(base, None, link) is None: | ||
# Doesn't look like a package - don't autobuild a wheel | ||
# because we'll have no way to lookup the result sanely | ||
continue | ||
if "binary" not in index.fmt_ctl_formats( | ||
# E.g. local directory. Build wheel just for this run. | ||
ephem_cache = True | ||
elif "binary" not in index.fmt_ctl_formats( | ||
self.finder.format_control, | ||
canonicalize_name(req.name)): | ||
logger.info( | ||
"Skipping bdist_wheel for %s, due to binaries " | ||
"being disabled for it.", req.name) | ||
continue | ||
buildset.append(req) | ||
buildset.append((req, ephem_cache)) | ||
|
||
if not buildset: | ||
return True | ||
|
||
# Build the wheels. | ||
logger.info( | ||
'Building wheels for collected packages: %s', | ||
', '.join([req.name for req in buildset]), | ||
', '.join([req.name for (req, _) in buildset]), | ||
) | ||
with indent_log(): | ||
build_success, build_failure = [], [] | ||
for req in buildset: | ||
for req, ephem in buildset: | ||
python_tag = None | ||
if autobuilding: | ||
python_tag = pep425tags.implementation_tag | ||
output_dir = self.wheel_cache.get_path_for_link(req.link) | ||
output_dir = self.wheel_cache.get_path_for_link(req.link, | ||
ephem=ephem) | ||
try: | ||
ensure_dir(output_dir) | ||
except OSError as e: | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -30,7 +30,7 @@ def test_no_clean_option_blocks_cleaning_after_install(script, data): | |||
build = script.base_path / 'pip-build' | ||||
script.pip( | ||||
'install', '--no-clean', '--no-index', '--build', build, | ||||
'--find-links=%s' % data.find_links, 'simple', | ||||
'--find-links=%s' % data.find_links, 'simple', expect_temp=True, | ||||
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 cache should be cleaning up after itself even if this happens? 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. This was controlled by the |
||||
) | ||||
assert exists(build) | ||||
|
||||
|
@@ -132,7 +132,7 @@ def test_cleanup_prevented_upon_build_dir_exception(script, data): | |||
result = script.pip( | ||||
'install', '-f', data.find_links, '--no-index', 'simple', | ||||
'--build', build, | ||||
expect_error=True, | ||||
expect_error=True, expect_temp=True, | ||||
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 cache should be cleaning up after itself even if this happens? 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. @takluyver Can you explain this? 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. Sorry, I can't remember the details. At some point some tests failed, and that seemed to be the right thing to make them work. 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. Perhaps the PR does not clean up the cache as advertised? What is the affect of this parameter? 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. AFAICT, this parameter means that the script run is expected to leave some temporary files, which is not what we want. 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. What we can do it turn the following line into a pip/src/pip/_internal/commands/install.py Line 222 in 6e2391a
Is there any other location where the wheelcache is initialized? 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. @xoviat -- a simple grep tells me there are 6 places. 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 So this test is named 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. Cool. That means that this change in tests corresponds to a change in the expected behaviour. :) PS: 41b83f8 was not the change I was suggesting. I thought there was no call to cleanup in finally. |
||||
) | ||||
|
||||
assert result.returncode == PREVIOUS_BUILD_DIR_ERROR | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,24 +68,26 @@ def test_install_subversion_usersite_editable_with_distribute( | |
) | ||
result.assert_installed('INITools', use_user_site=True) | ||
|
||
@pytest.mark.network | ||
def test_install_curdir_usersite(self, script, virtualenv, data): | ||
""" | ||
Test installing current directory ('.') into usersite | ||
""" | ||
virtualenv.system_site_packages = True | ||
script.pip("install", "wheel") | ||
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. Are you sure this is actually needed? 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. I have not validated this myself but from experience with related tests, I would strongly suspect that it is. 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. nit: use the |
||
run_from = data.packages.join("FSPkg") | ||
result = script.pip( | ||
'install', '-vvv', '--user', curdir, | ||
cwd=run_from, | ||
expect_error=False, | ||
) | ||
fspkg_folder = script.user_site / 'fspkg' | ||
egg_info_folder = ( | ||
script.user_site / 'FSPkg-0.1.dev0-py%s.egg-info' % pyversion | ||
dist_info_folder = ( | ||
script.user_site / 'FSPkg-0.1.dev0.dist-info' | ||
) | ||
assert fspkg_folder in result.files_created, result.stdout | ||
|
||
assert egg_info_folder in result.files_created | ||
assert dist_info_folder in result.files_created | ||
|
||
def test_install_user_venv_nositepkgs_fails(self, script, data): | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -193,7 +193,7 @@ def test_pip_wheel_fail_cause_of_previous_build_dir( | |
result = script.pip( | ||
'wheel', '--no-index', '--find-links=%s' % data.find_links, | ||
'--build', script.venv_path / 'build', | ||
'simple==3.0', expect_error=True, | ||
'simple==3.0', expect_error=True, expect_temp=True, | ||
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 cache should be cleaning up after itself even if this happens? 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. Ditto here for what I said below. 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. Ditto here for what I said below. ;) |
||
) | ||
|
||
# Then I see that the error code is the right one | ||
|
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.
Could you rephrase this to:
?