diff --git a/src/pip/_internal/commands/install.py b/src/pip/_internal/commands/install.py index f79c96487..bfa74f011 100644 --- a/src/pip/_internal/commands/install.py +++ b/src/pip/_internal/commands/install.py @@ -316,37 +316,50 @@ class InstallCommand(RequirementCommand): modifying_pip=requirement_set.has_requirement("pip") ) - # If caching is disabled don't try to build wheels. - if options.cache_dir: - # build wheels before install. - wb = WheelBuilder( - finder, preparer, wheel_cache, - build_options=[], global_options=[], - ) - # Ignore the result: a failed wheel will be - # installed from the sdist/vcs whatever. + # Consider legacy and PEP517-using requirements separately + legacy_requirements = [] + pep517_requirements = [] + for req in requirement_set.requirements.values(): + if req.use_pep517: + pep517_requirements.append(req) + else: + legacy_requirements.append(req) + + # We don't build wheels for legacy requirements if we + # don't have wheel installed or we don't have a cache dir + try: + import wheel # noqa: F401 + build_legacy = bool(options.cache_dir) + except ImportError: + build_legacy = False + + wb = WheelBuilder( + finder, preparer, wheel_cache, + build_options=[], global_options=[], + ) + + # Always build PEP 517 requirements + build_failures = wb.build( + pep517_requirements, + session=session, autobuilding=True + ) + + if build_legacy: + # We don't care about failures building legacy + # requirements, as we'll fall through to a direct + # install for those. wb.build( - requirement_set.requirements.values(), + pep517_requirements, session=session, autobuilding=True ) # If we're using PEP 517, we cannot do a direct install # so we fail here. - # TODO: Technically, if it's a setuptools-based project - # we could fall back to setup.py install even if we've - # been assuming PEP 517 to this point, but that would be - # complicated to achieve, as none of the legacy setup has - # been done. Better to get the user to specify - # --no-use-pep517. - failed_builds = [ - r for r in requirement_set.requirements.values() - if r.use_pep517 and not r.is_wheel - ] - - if failed_builds: + if build_failures: raise InstallationError( - "Could not build wheels for {}".format( - failed_builds)) + "Could not build wheels for {} which use" + + " PEP 517 and cannot be installed directly".format( + ", ".join(r.name for r in build_failures))) to_install = resolver.get_installation_order( requirement_set diff --git a/src/pip/_internal/commands/wheel.py b/src/pip/_internal/commands/wheel.py index 9c1f1497f..6dd07a785 100644 --- a/src/pip/_internal/commands/wheel.py +++ b/src/pip/_internal/commands/wheel.py @@ -167,10 +167,10 @@ class WheelCommand(RequirementCommand): global_options=options.global_options or [], no_clean=options.no_clean, ) - wheels_built_successfully = wb.build( + build_failures = wb.build( requirement_set.requirements.values(), session=session, ) - if not wheels_built_successfully: + if len(build_failures) != 0: raise CommandError( "Failed to build one or more wheels" ) diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py index 7033e96eb..9b6c86b77 100644 --- a/src/pip/_internal/req/req_install.py +++ b/src/pip/_internal/req/req_install.py @@ -541,7 +541,6 @@ class InstallRequirement(object): show_stdout=False, command_desc='python setup.py egg_info') - @property def egg_info_path(self): if self._egg_info_path is None: diff --git a/src/pip/_internal/wheel.py b/src/pip/_internal/wheel.py index 3997e06d8..12f05cf7b 100644 --- a/src/pip/_internal/wheel.py +++ b/src/pip/_internal/wheel.py @@ -766,6 +766,8 @@ class WheelBuilder(object): from pip._internal import index from pip._internal.models.link import Link + # TODO: This check fails if --no-cache-dir is set. And yet we + # might be able to build into the ephemeral cache, surely? building_is_possible = self._wheel_dir or ( autobuilding and self.wheel_cache.cache_dir ) @@ -806,7 +808,7 @@ class WheelBuilder(object): buildset.append((req, ephem_cache)) if not buildset: - return True + return [] # Build the wheels. logger.info( @@ -879,4 +881,4 @@ class WheelBuilder(object): ' '.join([req.name for req in build_failure]), ) # Return True if all builds were successful - return len(build_failure) == 0 + return build_failure