예제 #1
0
    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
예제 #2
0
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)
예제 #3
0
    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
예제 #4
0
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
예제 #5
0
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()]
예제 #6
0
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
예제 #7
0
    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
예제 #8
0
    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
예제 #9
0
    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
예제 #10
0
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
예제 #11
0
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
예제 #12
0
    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
예제 #13
0
    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)
예제 #14
0
    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:
예제 #15
0
    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)
예제 #16
0
        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)
=======
예제 #17
0
파일: resolver.py 프로젝트: GuyTuval/pip
    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
예제 #18
0
파일: resolver.py 프로젝트: bmartinn/pip
    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
예제 #19
0
    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
예제 #20
0
    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
예제 #21
0
파일: resolver.py 프로젝트: rkm/pip
    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
예제 #22
0
    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
예제 #23
0
    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
예제 #24
0
파일: resolver.py 프로젝트: klocsson/pip
    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
예제 #25
0
    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
예제 #26
0
=======
        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