def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet """Resolve what operations need to be done As a side-effect of this method, the packages (and their dependencies) are downloaded, unpacked and prepared for installation. This preparation is done by ``pip.operations.prepare``. Once PyPI has static dependency metadata available, it would be possible to move the preparation to become a step separated from dependency resolution. """ requirement_set = RequirementSet( check_supported_wheels=check_supported_wheels) for req in root_reqs: requirement_set.add_requirement(req) # Actually prepare the files, and collect any exceptions. Most hash # exceptions cannot be checked ahead of time, because # _populate_link() needs to be called before we can make decisions # based on link type. discovered_reqs = [] # type: List[InstallRequirement] hash_errors = HashErrors() for req in chain(root_reqs, discovered_reqs): try: discovered_reqs.extend(self._resolve_one(requirement_set, req)) except HashError as exc: exc.req = req hash_errors.append(exc) if hash_errors: raise hash_errors return requirement_set
def get_requirements(args: Iterable[str]) -> List[InstallRequirement]: requirement_set = RequirementSet() for req in args: req_to_add = install_req_from_line(req, comes_from=None) req_to_add.is_direct = True requirement_set.add_requirement(req_to_add) return cast(List[InstallRequirement], requirement_set.all_requirements)
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet # FIXME: Implement constraints. if any(r.constraint for r in root_reqs): raise InstallationError("Constraints are not yet supported.") provider = PipProvider( factory=self.factory, ignore_dependencies=self.ignore_dependencies, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) requirements = [ self.factory.make_requirement_from_install_req(r) for r in root_reqs ] try: self._result = resolver.resolve(requirements) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) if not error: # TODO: This needs fixing, we need to look at the # factory.get_installation_error infrastructure, as that # doesn't really allow for the logger.critical calls I'm # using here. for req, parent in e.causes: logger.critical( "Could not find a version that satisfies " + "the requirement " + str(req) + ("" if parent is None else " (from {})".format( parent.name )) ) raise InstallationError( "No matching distribution found for " + ", ".join([r.name for r, _ in e.causes]) ) raise six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = provider.get_install_requirement(candidate) if ireq is None: continue ireq.should_reinstall = self.factory.should_reinstall(candidate) req_set.add_named_requirement(ireq) return req_set
def test_new_resolver_get_installation_order(resolver, edges, ordered_reqs): graph = _make_graph(edges) # Mapping values and criteria are not used in test, so we stub them out. mapping = {vertex: None for vertex in graph if vertex is not None} resolver._result = Result(mapping, graph, criteria=None) reqset = RequirementSet() for r in ordered_reqs: reqset.add_named_requirement(install_req_from_line(r)) ireqs = resolver.get_installation_order(reqset) req_strs = [str(r.req) for r in ireqs] assert req_strs == ordered_reqs
def get_supported_wheels(wheel_directory): requirement_set = RequirementSet() for f in os.listdir(wheel_directory): wheel_filename = os.path.join(wheel_directory, f) requirement = install_req_from_line(wheel_filename) requirement.is_direct = True try: requirement_set.add_requirement(requirement) except InstallationError: # This deliberately filters out incompatible requirements. pass return [req.link.path for req in requirement_set.requirements.values()]
def test_deprecation_notice_for_pip_install_options(recwarn): install_options = ["--prefix=/hello"] req_set = RequirementSet() warn_deprecated_install_options(req_set, install_options) assert len(recwarn) == 1 message = recwarn[0].message.args[0] assert "['--prefix'] from command line" in message
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet provider = PipProvider( factory=self.factory, ignore_dependencies=self.ignore_dependencies, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) requirements = [self.factory.make_requirement(r) for r in root_reqs] self._result = resolver.resolve(requirements) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = provider.get_install_requirement(candidate) if ireq is not None: req_set.add_named_requirement(ireq) return req_set
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet provider = PipProvider( self.finder, self.preparer, self.make_install_req, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) requirements = [provider.make_requirement(r) for r in root_reqs] self._result = resolver.resolve(requirements) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = provider.get_install_requirement(candidate) req_set.add_named_requirement(ireq) return req_set
def test_exclusive_environment_markers( self, monkeypatch: pytest.MonkeyPatch) -> None: """Make sure excluding environment markers are handled correctly.""" # GIVEN resolver = make_test_resolver(monkeypatch, []) requirement_set = RequirementSet(check_supported_wheels=True) eq36 = install_req_from_line( "Django>=1.6.10,<1.7 ; python_version == '3.6'") eq36.user_supplied = True ne36 = install_req_from_line( "Django>=1.6.10,<1.8 ; python_version != '3.6'") ne36.user_supplied = True # WHEN resolver._add_requirement_to_set(requirement_set, eq36) resolver._add_requirement_to_set(requirement_set, ne36) # THEN assert requirement_set.has_requirement("Django") assert len(requirement_set.all_requirements) == 1
def test_deprecation_notice_for_requirement_options(recwarn): install_options = [] req_set = RequirementSet() bad_named_req_options = {"install_options": ["--home=/wow"]} bad_named_req = InstallRequirement(Requirement("hello"), "requirements.txt", options=bad_named_req_options) req_set.add_named_requirement(bad_named_req) bad_unnamed_req_options = {"install_options": ["--install-lib=/lib"]} bad_unnamed_req = InstallRequirement(None, "requirements2.txt", options=bad_unnamed_req_options) req_set.add_unnamed_requirement(bad_unnamed_req) warn_deprecated_install_options(req_set, install_options) assert len(recwarn) == 1 message = recwarn[0].message.args[0] assert ( "['--install-lib'] from <InstallRequirement> (from requirements2.txt)" in message) assert "['--home'] from hello (from requirements.txt)" in message
def test_new_resolver_get_installation_order(resolver, edges, ordered_reqs): # Build graph from edge declarations. graph = DirectedGraph() for parent, child in edges: parent = canonicalize_name(parent) if parent else None child = canonicalize_name(child) if child else None for v in (parent, child): if v not in graph: graph.add(v) graph.connect(parent, child) # Mapping values and criteria are not used in test, so we stub them out. mapping = {vertex: None for vertex in graph if vertex is not None} resolver._result = Result(mapping, graph, criteria=None) reqset = RequirementSet() for r in ordered_reqs: reqset.add_named_requirement(install_req_from_line(r)) ireqs = resolver.get_installation_order(reqset) req_strs = [str(r.req) for r in ireqs] assert req_strs == ordered_reqs
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet # FIXME: Implement constraints. if any(r.constraint for r in root_reqs): raise InstallationError("Constraints are not yet supported.") provider = PipProvider( factory=self.factory, ignore_dependencies=self.ignore_dependencies, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) requirements = [ self.factory.make_requirement_from_install_req(r) for r in root_reqs ] try: self._result = resolver.resolve(requirements) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) if not error: raise six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = provider.get_install_requirement(candidate) if ireq is None: continue ireq.should_reinstall = self.factory.should_reinstall(candidate) req_set.add_named_requirement(ireq) return req_set
def test_unsupported_wheel_link_requirement_raises( self, monkeypatch: pytest.MonkeyPatch) -> None: # GIVEN resolver = make_test_resolver(monkeypatch, []) requirement_set = RequirementSet(check_supported_wheels=True) install_req = install_req_from_line( "https://whatever.com/peppercorn-0.4-py2.py3-bogus-any.whl", ) assert install_req.link is not None assert install_req.link.is_wheel assert install_req.link.scheme == "https" # WHEN / THEN with pytest.raises(InstallationError): resolver._add_requirement_to_set(requirement_set, install_req)
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet """Resolve what operations need to be done As a side-effect of this method, the packages (and their dependencies) are downloaded, unpacked and prepared for installation. This preparation is done by ``pip.operations.prepare``. Once PyPI has static dependency metadata available, it would be possible to move the preparation to become a step separated from dependency resolution. """ requirement_set = RequirementSet( check_supported_wheels=check_supported_wheels ) for req in root_reqs:
def test_unsupported_wheel_local_file_requirement_raises( self, data: TestData, monkeypatch: pytest.MonkeyPatch) -> None: # GIVEN resolver = make_test_resolver(monkeypatch, []) requirement_set = RequirementSet(check_supported_wheels=True) install_req = install_req_from_line( os.fspath( data.packages.joinpath( "simple.dist-0.1-py1-none-invalid.whl")), ) assert install_req.link is not None assert install_req.link.is_wheel assert install_req.link.scheme == "file" # WHEN / THEN with pytest.raises(InstallationError): resolver._add_requirement_to_set(requirement_set, install_req)
finder, # type: PackageFinder session, # type: PipSession <<<<<<< HEAD ======= check_supported_wheels=True, # type: bool >>>>>>> b66a76afa15ab74019740676a52a071b85ed8f71 ): # type: (...) -> List[InstallRequirement] """ Parse command-line arguments into the corresponding requirements. """ <<<<<<< HEAD requirements = [] # type: List[InstallRequirement] ======= requirement_set = RequirementSet( check_supported_wheels=check_supported_wheels ) >>>>>>> b66a76afa15ab74019740676a52a071b85ed8f71 for filename in options.constraints: for parsed_req in parse_requirements( filename, constraint=True, finder=finder, options=options, session=session): req_to_add = install_req_from_parsed_requirement( parsed_req, isolated=options.isolated_mode, <<<<<<< HEAD user_supplied=False, ) requirements.append(req_to_add) =======
def resolve( self, root_reqs: List[InstallRequirement], check_supported_wheels: bool ) -> RequirementSet: collected = self.factory.collect_root_requirements(root_reqs) provider = PipProvider( factory=self.factory, constraints=collected.constraints, ignore_dependencies=self.ignore_dependencies, upgrade_strategy=self.upgrade_strategy, user_requested=collected.user_requested, ) if "PIP_RESOLVER_DEBUG" in os.environ: reporter: BaseReporter = PipDebuggingReporter() else: reporter = PipReporter() resolver: RLResolver[Requirement, Candidate, str] = RLResolver( provider, reporter, ) try: try_to_avoid_resolution_too_deep = 2000000 result = self._result = resolver.resolve( collected.requirements, max_rounds=try_to_avoid_resolution_too_deep ) except ResolutionImpossible as e: error = self.factory.get_installation_error( cast("ResolutionImpossible[Requirement, Candidate]", e), collected.constraints, ) raise error from e req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in result.mapping.values(): ireq = candidate.get_install_requirement() if ireq is None: continue # Check if there is already an installation under the same name, # and set a flag for later stages to uninstall it, if needed. installed_dist = self.factory.get_dist_to_uninstall(candidate) if installed_dist is None: # There is no existing installation -- nothing to uninstall. ireq.should_reinstall = False elif self.factory.force_reinstall: # The --force-reinstall flag is set -- reinstall. ireq.should_reinstall = True elif parse_version(installed_dist.version) != candidate.version: # The installation is different in version -- reinstall. ireq.should_reinstall = True elif candidate.is_editable or dist_is_editable(installed_dist): # The incoming distribution is editable, or different in # editable-ness to installation -- reinstall. ireq.should_reinstall = True elif candidate.source_link and candidate.source_link.is_file: # The incoming distribution is under file:// if candidate.source_link.is_wheel: # is a local wheel -- do nothing. logger.info( "%s is already installed with the same version as the " "provided wheel. Use --force-reinstall to force an " "installation of the wheel.", ireq.name, ) continue looks_like_sdist = ( is_archive_file(candidate.source_link.file_path) and candidate.source_link.ext != ".zip" ) if looks_like_sdist: # is a local sdist -- show a deprecation warning! reason = ( "Source distribution is being reinstalled despite an " "installed package having the same name and version as " "the installed package." ) replacement = "use --force-reinstall" deprecated( reason=reason, replacement=replacement, gone_in="21.2", issue=8711, ) # is a local sdist or path -- reinstall ireq.should_reinstall = True else: continue link = candidate.source_link if link and link.is_yanked: # The reason can contain non-ASCII characters, Unicode # is required for Python 2. msg = ( "The candidate selected for download or install is a " "yanked version: {name!r} candidate (version {version} " "at {link})\nReason for being yanked: {reason}" ).format( name=candidate.name, version=candidate.version, link=link, reason=link.yanked_reason or "<none given>", ) logger.warning(msg) req_set.add_named_requirement(ireq) reqs = req_set.all_requirements self.factory.preparer.prepare_linked_requirements_more(reqs) return req_set
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet # The factory should not have retained state from any previous usage. # In theory this could only happen if self was reused to do a second # resolve, which isn't something we do at the moment. We assert here # in order to catch the issue if that ever changes. # The persistent state that we care about is `root_reqs`. assert len(self.factory.root_reqs) == 0, "Factory is being re-used" # FIXME: Implement constraints. if any(r.constraint for r in root_reqs): raise InstallationError("Constraints are not yet supported.") provider = PipProvider( factory=self.factory, ignore_dependencies=self.ignore_dependencies, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) requirements = [ self.factory.make_requirement_from_install_req(r) for r in root_reqs ] try: self._result = resolver.resolve(requirements) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) if not error: # TODO: This needs fixing, we need to look at the # factory.get_installation_error infrastructure, as that # doesn't really allow for the logger.critical calls I'm # using here. for req, parent in e.causes: logger.critical( "Could not find a version that satisfies " + "the requirement " + str(req) + ("" if parent is None else " (from {})".format( parent.name )) ) raise InstallationError( "No matching distribution found for " + ", ".join([r.name for r, _ in e.causes]) ) raise six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = provider.get_install_requirement(candidate) if ireq is None: continue ireq.should_reinstall = self.factory.should_reinstall(candidate) req_set.add_named_requirement(ireq) return req_set
def _add_requirement_to_set( self, requirement_set: RequirementSet, install_req: InstallRequirement, parent_req_name: Optional[str] = None, extras_requested: Optional[Iterable[str]] = None, ) -> Tuple[List[InstallRequirement], Optional[InstallRequirement]]: """Add install_req as a requirement to install. :param parent_req_name: The name of the requirement that needed this added. The name is used because when multiple unnamed requirements resolve to the same name, we could otherwise end up with dependency links that point outside the Requirements set. parent_req must already be added. Note that None implies that this is a user supplied requirement, vs an inferred one. :param extras_requested: an iterable of extras used to evaluate the environment markers. :return: Additional requirements to scan. That is either [] if the requirement is not applicable, or [install_req] if the requirement is applicable and has just been added. """ # If the markers do not match, ignore this requirement. if not install_req.match_markers(extras_requested): logger.info( "Ignoring %s: markers '%s' don't match your environment", install_req.name, install_req.markers, ) return [], None # If the wheel is not supported, raise an error. # Should check this after filtering out based on environment markers to # allow specifying different wheels based on the environment/OS, in a # single requirements file. if install_req.link and install_req.link.is_wheel: wheel = Wheel(install_req.link.filename) tags = compatibility_tags.get_supported() if requirement_set.check_supported_wheels and not wheel.supported( tags): raise InstallationError( "{} is not a supported wheel on this platform.".format( wheel.filename)) # This next bit is really a sanity check. assert (not install_req.user_supplied or parent_req_name is None ), "a user supplied req shouldn't have a parent" # Unnamed requirements are scanned again and the requirement won't be # added as a dependency until after scanning. if not install_req.name: requirement_set.add_unnamed_requirement(install_req) return [install_req], None try: existing_req: Optional[ InstallRequirement] = requirement_set.get_requirement( install_req.name) except KeyError: existing_req = None has_conflicting_requirement = ( parent_req_name is None and existing_req and not existing_req.constraint and existing_req.extras == install_req.extras and existing_req.req and install_req.req and existing_req.req.specifier != install_req.req.specifier) if has_conflicting_requirement: raise InstallationError( "Double requirement given: {} (already in {}, name={!r})". format(install_req, existing_req, install_req.name)) # When no existing requirement exists, add the requirement as a # dependency and it will be scanned again after. if not existing_req: requirement_set.add_named_requirement(install_req) # We'd want to rescan this requirement later return [install_req], install_req # Assume there's no need to scan, and that we've already # encountered this for scanning. if install_req.constraint or not existing_req.constraint: return [], existing_req does_not_satisfy_constraint = install_req.link and not ( existing_req.link and install_req.link.path == existing_req.link.path) if does_not_satisfy_constraint: raise InstallationError("Could not satisfy constraints for '{}': " "installation from path or url cannot be " "constrained to a version".format( install_req.name)) # If we're now installing a constraint, mark the existing # object for real installation. existing_req.constraint = False # If we're now installing a user supplied requirement, # mark the existing object as such. if install_req.user_supplied: existing_req.user_supplied = True existing_req.extras = tuple( sorted(set(existing_req.extras) | set(install_req.extras))) logger.debug( "Setting %s extras to: %s", existing_req, existing_req.extras, ) # Return the existing requirement for addition to the parent and # scanning again. return [existing_req], existing_req
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet constraints = {} # type: Dict[str, SpecifierSet] user_requested = set() # type: Set[str] requirements = [] for req in root_reqs: if req.constraint: # Ensure we only accept valid constraints problem = check_invalid_constraint_type(req) if problem: raise InstallationError(problem) if not req.match_markers(): continue name = canonicalize_name(req.name) if name in constraints: constraints[name] = constraints[name] & req.specifier else: constraints[name] = req.specifier else: if req.user_supplied and req.name: user_requested.add(canonicalize_name(req.name)) r = self.factory.make_requirement_from_install_req( req, requested_extras=(), ) if r is not None: requirements.append(r) provider = PipProvider( factory=self.factory, constraints=constraints, ignore_dependencies=self.ignore_dependencies, upgrade_strategy=self.upgrade_strategy, user_requested=user_requested, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) try: try_to_avoid_resolution_too_deep = 2000000 self._result = resolver.resolve( requirements, max_rounds=try_to_avoid_resolution_too_deep, ) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = candidate.get_install_requirement() if ireq is None: continue # Check if there is already an installation under the same name, # and set a flag for later stages to uninstall it, if needed. # * There isn't, good -- no uninstalltion needed. # * The --force-reinstall flag is set. Always reinstall. # * The installation is different in version or editable-ness, so # we need to uninstall it to install the new distribution. # * The installed version is the same as the pending distribution. # Skip this distrubiton altogether to save work. installed_dist = self.factory.get_dist_to_uninstall(candidate) if installed_dist is None: ireq.should_reinstall = False elif self.factory.force_reinstall: ireq.should_reinstall = True elif installed_dist.parsed_version != candidate.version: ireq.should_reinstall = True elif dist_is_editable(installed_dist) != candidate.is_editable: ireq.should_reinstall = True else: continue link = candidate.source_link if link and link.is_yanked: # The reason can contain non-ASCII characters, Unicode # is required for Python 2. msg = ( u'The candidate selected for download or install is a ' u'yanked version: {name!r} candidate (version {version} ' u'at {link})\nReason for being yanked: {reason}').format( name=candidate.name, version=candidate.version, link=link, reason=link.yanked_reason or u'<none given>', ) logger.warning(msg) req_set.add_named_requirement(ireq) return req_set
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet constraints = {} # type: Dict[str, SpecifierSet] user_requested = set() # type: Set[str] requirements = [] for req in root_reqs: if not req.match_markers(): continue if req.constraint: # Ensure we only accept valid constraints reject_invalid_constraint_types(req) name = canonicalize_name(req.name) if name in constraints: constraints[name] = constraints[name] & req.specifier else: constraints[name] = req.specifier else: if req.is_direct and req.name: user_requested.add(canonicalize_name(req.name)) requirements.append( self.factory.make_requirement_from_install_req(req)) provider = PipProvider( factory=self.factory, constraints=constraints, ignore_dependencies=self.ignore_dependencies, upgrade_strategy=self.upgrade_strategy, user_requested=user_requested, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) try: try_to_avoid_resolution_too_deep = 2000000 self._result = resolver.resolve( requirements, max_rounds=try_to_avoid_resolution_too_deep, ) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) if not error: # TODO: This needs fixing, we need to look at the # factory.get_installation_error infrastructure, as that # doesn't really allow for the logger.critical calls I'm # using here. for req, parent in e.causes: logger.critical( "Could not find a version that satisfies " + "the requirement " + str(req) + ("" if parent is None else " (from {})".format(parent. name))) raise DistributionNotFound( "No matching distribution found for " + ", ".join([r.name for r, _ in e.causes])) six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = candidate.get_install_requirement() if ireq is None: continue ireq.should_reinstall = self.factory.should_reinstall(candidate) req_set.add_named_requirement(ireq) return req_set
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet constraints = {} # type: Dict[str, Constraint] user_requested = set() # type: Set[str] requirements = [] for req in root_reqs: if req.constraint: # Ensure we only accept valid constraints problem = check_invalid_constraint_type(req) if problem: raise InstallationError(problem) if not req.match_markers(): continue name = canonicalize_name(req.name) if name in constraints: constraints[name] &= req else: constraints[name] = Constraint.from_ireq(req) else: if req.user_supplied and req.name: user_requested.add(canonicalize_name(req.name)) r = self.factory.make_requirement_from_install_req( req, requested_extras=(), ) if r is not None: requirements.append(r) provider = PipProvider( factory=self.factory, constraints=constraints, ignore_dependencies=self.ignore_dependencies, upgrade_strategy=self.upgrade_strategy, user_requested=user_requested, ) if "PIP_RESOLVER_DEBUG" in os.environ: reporter = PipDebuggingReporter() else: reporter = PipReporter() resolver = RLResolver(provider, reporter) try: try_to_avoid_resolution_too_deep = 2000000 self._result = resolver.resolve( requirements, max_rounds=try_to_avoid_resolution_too_deep, ) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = candidate.get_install_requirement() if ireq is None: continue # Check if there is already an installation under the same name, # and set a flag for later stages to uninstall it, if needed. installed_dist = self.factory.get_dist_to_uninstall(candidate) if installed_dist is None: # There is no existing installation -- nothing to uninstall. ireq.should_reinstall = False elif self.factory.force_reinstall: # The --force-reinstall flag is set -- reinstall. ireq.should_reinstall = True elif installed_dist.parsed_version != candidate.version: # The installation is different in version -- reinstall. ireq.should_reinstall = True elif candidate.is_editable or dist_is_editable(installed_dist): # The incoming distribution is editable, or different in # editable-ness to installation -- reinstall. ireq.should_reinstall = True elif candidate.source_link.is_file: # The incoming distribution is under file:// if candidate.source_link.is_wheel: # is a local wheel -- do nothing. logger.info( "%s is already installed with the same version as the " "provided wheel. Use --force-reinstall to force an " "installation of the wheel.", ireq.name, ) continue looks_like_sdist = (is_archive_file( candidate.source_link.file_path) and candidate.source_link.ext != ".zip") if looks_like_sdist: # is a local sdist -- show a deprecation warning! reason = ( "Source distribution is being reinstalled despite an " "installed package having the same name and version as " "the installed package.") replacement = "use --force-reinstall" deprecated( reason=reason, replacement=replacement, gone_in="21.1", issue=8711, ) # is a local sdist or path -- reinstall ireq.should_reinstall = True else: continue link = candidate.source_link if link and link.is_yanked: # The reason can contain non-ASCII characters, Unicode # is required for Python 2. msg = ('The candidate selected for download or install is a ' 'yanked version: {name!r} candidate (version {version} ' 'at {link})\nReason for being yanked: {reason}').format( name=candidate.name, version=candidate.version, link=link, reason=link.yanked_reason or '<none given>', ) logger.warning(msg) req_set.add_named_requirement(ireq) reqs = req_set.all_requirements self.factory.preparer.prepare_linked_requirements_more(reqs) return req_set
def get_requirements( self, args, # type: List[str] options, # type: Values finder, # type: PackageFinder session, # type: PipSession check_supported_wheels=True, # type: bool ): # type: (...) -> List[InstallRequirement] """ Parse command-line arguments into the corresponding requirements. """ requirement_set = RequirementSet( check_supported_wheels=check_supported_wheels) for filename in options.constraints: for parsed_req in parse_requirements( filename, constraint=True, finder=finder, options=options, session=session, ): req_to_add = install_req_from_parsed_requirement( parsed_req, isolated=options.isolated_mode, ) req_to_add.is_direct = True requirement_set.add_requirement(req_to_add) for req in args: req_to_add = install_req_from_line( req, None, isolated=options.isolated_mode, use_pep517=options.use_pep517, ) req_to_add.is_direct = True requirement_set.add_requirement(req_to_add) for req in options.editables: req_to_add = install_req_from_editable( req, isolated=options.isolated_mode, use_pep517=options.use_pep517, ) req_to_add.is_direct = True requirement_set.add_requirement(req_to_add) # NOTE: options.require_hashes may be set if --require-hashes is True for filename in options.requirements: for parsed_req in parse_requirements(filename, finder=finder, options=options, session=session): req_to_add = install_req_from_parsed_requirement( parsed_req, isolated=options.isolated_mode, use_pep517=options.use_pep517, ) req_to_add.is_direct = True requirement_set.add_requirement(req_to_add) # If any requirement has hash options, enable hash checking. requirements = requirement_set.all_requirements if any(req.has_hash_options for req in requirements): options.require_hashes = True if not (args or options.editables or options.requirements): opts = {"name": self.name} if options.find_links: raise CommandError( "You must give at least one requirement to {name} " '(maybe you meant "pip {name} {links}"?)'.format( **dict(opts, links=" ".join(options.find_links)))) else: raise CommandError( "You must give at least one requirement to {name} " '(see "pip help {name}")'.format(**opts)) return requirements
def resolve(self, root_reqs, check_supported_wheels): # type: (List[InstallRequirement], bool) -> RequirementSet constraints = {} # type: Dict[str, SpecifierSet] user_requested = set() # type: Set[str] requirements = [] for req in root_reqs: if req.constraint: # Ensure we only accept valid constraints reject_invalid_constraint_types(req) name = canonicalize_name(req.name) if name in constraints: constraints[name] = constraints[name] & req.specifier else: constraints[name] = req.specifier else: if req.is_direct and req.name: user_requested.add(canonicalize_name(req.name)) r = self.factory.make_requirement_from_install_req( req, requested_extras=(), ) if r is not None: requirements.append(r) provider = PipProvider( factory=self.factory, constraints=constraints, ignore_dependencies=self.ignore_dependencies, upgrade_strategy=self.upgrade_strategy, user_requested=user_requested, ) reporter = BaseReporter() resolver = RLResolver(provider, reporter) try: try_to_avoid_resolution_too_deep = 2000000 self._result = resolver.resolve( requirements, max_rounds=try_to_avoid_resolution_too_deep, ) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = candidate.get_install_requirement() if ireq is None: continue link = candidate.source_link if link and link.is_yanked: # The reason can contain non-ASCII characters, Unicode # is required for Python 2. msg = ( u'The candidate selected for download or install is a ' u'yanked version: {name!r} candidate (version {version} ' u'at {link})\nReason for being yanked: {reason}').format( name=candidate.name, version=candidate.version, link=link, reason=link.yanked_reason or u'<none given>', ) logger.warning(msg) ireq.should_reinstall = self.factory.should_reinstall(candidate) req_set.add_named_requirement(ireq) return req_set
def _resolve_one( self, requirement_set: RequirementSet, req_to_install: InstallRequirement, ) -> List[InstallRequirement]: """Prepare a single requirements file. :return: A list of additional InstallRequirements to also install. """ # Tell user what we are doing for this requirement: # obtain (editable), skipping, processing (local url), collecting # (remote url or package name) if req_to_install.constraint or req_to_install.prepared: return [] req_to_install.prepared = True # Parse and return dependencies dist = self._get_dist_for(req_to_install) # This will raise UnsupportedPythonVersion if the given Python # version isn't compatible with the distribution's Requires-Python. _check_dist_requires_python( dist, version_info=self._py_version_info, ignore_requires_python=self.ignore_requires_python, ) more_reqs: List[InstallRequirement] = [] def add_req(subreq: Distribution, extras_requested: Iterable[str]) -> None: sub_install_req = self._make_install_req( str(subreq), req_to_install, ) parent_req_name = req_to_install.name to_scan_again, add_to_parent = requirement_set.add_requirement( sub_install_req, parent_req_name=parent_req_name, extras_requested=extras_requested, ) if parent_req_name and add_to_parent: self._discovered_dependencies[parent_req_name].append( add_to_parent) more_reqs.extend(to_scan_again) with indent_log(): # We add req_to_install before its dependencies, so that we # can refer to it when adding dependencies. if not requirement_set.has_requirement(req_to_install.name): # 'unnamed' requirements will get added here # 'unnamed' requirements can only come from being directly # provided by the user. assert req_to_install.user_supplied requirement_set.add_requirement(req_to_install, parent_req_name=None) if not self.ignore_dependencies: if req_to_install.extras: logger.debug( "Installing extra requirements: %r", ",".join(req_to_install.extras), ) missing_requested = sorted( set(req_to_install.extras) - set(dist.extras)) for missing in missing_requested: logger.warning("%s does not provide the extra '%s'", dist, missing) available_requested = sorted( set(dist.extras) & set(req_to_install.extras)) for subreq in dist.requires(available_requested): add_req(subreq, extras_requested=available_requested) return more_reqs
======= reporter = BaseReporter() >>>>>>> 74c061954d5e927be4caafbd793e96a50563c265 resolver = RLResolver(provider, reporter) try: try_to_avoid_resolution_too_deep = 2000000 self._result = resolver.resolve( requirements, max_rounds=try_to_avoid_resolution_too_deep, ) except ResolutionImpossible as e: error = self.factory.get_installation_error(e) six.raise_from(error, e) req_set = RequirementSet(check_supported_wheels=check_supported_wheels) for candidate in self._result.mapping.values(): ireq = candidate.get_install_requirement() if ireq is None: continue # Check if there is already an installation under the same name, # and set a flag for later stages to uninstall it, if needed. <<<<<<< HEAD installed_dist = self.factory.get_dist_to_uninstall(candidate) if installed_dist is None: # There is no existing installation -- nothing to uninstall. ireq.should_reinstall = False elif self.factory.force_reinstall: # The --force-reinstall flag is set -- reinstall. ireq.should_reinstall = True