Exemple #1
0
def _generate_no_candidate_display(req, repo, dists, failure):
    """Print a human friendly display to stderr when compilation fails"""
    failing_node = dists[req.name]
    constraints = failing_node.build_constraints()

    can_satisfy = True
    no_candidates = False

    if isinstance(failure, NoCandidateException):
        try:
            can_satisfy = is_possible(constraints)
        except (ValueError, TypeError):
            can_satisfy = True

        all_candidates = {repo: repo.get_candidates(req) for repo in repo}
        no_candidates = (
            sum(len(candidates) for candidates in all_candidates.values()) == 0
        )

        if not can_satisfy:
            print(
                "No version of {} could possibly satisfy the following requirements ({}):".format(
                    req.name, constraints
                ),
                file=sys.stderr,
            )
        elif no_candidates:
            print(
                "No candidates found for {} in any of the input sources. Required by:".format(
                    req.name
                ),
                file=sys.stderr,
            )
        else:
            print(
                "No version of {} could satisfy the following requirements ({}):".format(
                    req.name, constraints
                ),
                file=sys.stderr,
            )
    else:
        print(
            "A problem occurred while determining requirements for {name}:\n"
            "{failure}".format(name=req.name, failure=failure),
            file=sys.stderr,
        )

    paths = _find_paths_to_root(failing_node)
    _print_paths_to_root(failing_node, paths, True)

    if can_satisfy and not no_candidates:
        _dump_repo_candidates(req, repo)
Exemple #2
0
def compile_roots(
    node,  # type: DependencyNode
    source,  # type: Optional[DependencyNode]
    repo,  # type: BaseRepository
    dists,  # type: DistributionCollection
    options,  # type: CompileOptions
    depth=1,  # type: int
    max_downgrade=MAX_DOWNGRADE,  # type: int
    _path=None,
):  # pylint: disable=too-many-statements,too-many-locals,too-many-branches
    # type: (...) -> None
    """
    Args:
        node: The node to compile
        source: The source node of this provided node. This is used to build the graph
        repo: The repository to provide candidates.
        dists: The solution that is being built incrementally
        options: Static options for the compile (including extras)
        depth: Depth the compilation has descended into
        max_downgrade: The maximum number of version downgrades that will be allowed for conflicts
        _path: The path back to root - all nodes along the way
    """
    if _path is None:
        _path = set()

    logger = LOG
    logger.debug("Processing node %s", node)
    if node.key in dists and dists[node.key] is not node:
        logger.debug("No need to process this node, it has been removed")
    elif node.metadata is not None:
        if not node.complete:
            if depth > MAX_COMPILE_DEPTH:
                raise ValueError("Recursion too deep")
            try:
                for req in sorted(node.dependencies,
                                  key=lambda node: node.key):
                    if req in _path:
                        if options.allow_circular_dependencies:
                            logger.error(
                                "Skipping node %s because it includes this node",
                                req,
                            )
                        else:
                            raise ValueError(
                                "Circular dependency: {node} -> {req} -> {node}"
                                .format(
                                    node=node,
                                    req=req,
                                ))
                    else:
                        compile_roots(
                            req,
                            node,
                            repo,
                            dists,
                            options,
                            depth=depth + 1,
                            max_downgrade=max_downgrade,
                            _path=_path | {node},
                        )
                node.complete = True

            except NoCandidateException:
                if max_downgrade == 0:
                    raise
                compile_roots(
                    node,
                    source,
                    repo,
                    dists,
                    options,
                    depth=depth,
                    max_downgrade=0,
                    _path=_path,
                )
        else:
            logger.info("Reusing dist %s %s", node.metadata.name,
                        node.metadata.version)
    else:
        spec_req = node.build_constraints()

        if options.pinned_requirements:
            pin = options.pinned_requirements.get(
                normalize_project_name(spec_req.project_name), spec_req)
            spec_req = merge_requirements(spec_req, pin)

        try:
            metadata, cached = repo.get_candidate(spec_req,
                                                  max_downgrade=max_downgrade)
            logger.debug(
                "Acquired candidate %s %s [%s] (%s)",
                metadata,
                spec_req,
                metadata.origin,
                "cached" if cached else "download",
            )
            reason = None
            if source is not None:
                if node in source.dependencies:
                    reason = source.dependencies[node]
                    if options.extras and isinstance(metadata.origin,
                                                     SourceRepository):
                        reason = merge_requirements(
                            reason,
                            parse_requirement(reason.project_name + "[" +
                                              ",".join(options.extras) + "]"),
                        )

            nodes_to_recurse = dists.add_dist(metadata, source, reason)
            for recurse_node in sorted(nodes_to_recurse):
                compile_roots(
                    recurse_node,
                    source,
                    repo,
                    dists,
                    options,
                    depth=depth + 1,
                    max_downgrade=max_downgrade,
                    _path=_path,
                )
        except NoCandidateException:
            if max_downgrade == 0:
                raise

            exc_info = sys.exc_info()

            nodes = sorted(node.reverse_deps)

            violate_score = defaultdict(int)  # type: Dict[DependencyNode, int]
            for idx, revnode in enumerate(nodes):
                for next_node in nodes[idx + 1:]:
                    if not is_possible(
                            merge_requirements(revnode.dependencies[node],
                                               next_node.dependencies[node])):
                        logger.error(
                            "Requirement %s was not possible. Violating pair: %s %s",
                            node.build_constraints(),
                            revnode,
                            next_node,
                        )
                        violate_score[revnode] += 1
                        violate_score[next_node] += 1

            try:
                baddest_node = next(
                    node for node, _ in sorted(violate_score.items(),
                                               key=operator.itemgetter(1))
                    if node.metadata is not None and not node.metadata.meta)
            except StopIteration:
                six.reraise(*exc_info)

            bad_meta = baddest_node.metadata
            assert bad_meta is not None
            logger.debug("The node %s had the most conflicts", baddest_node)

            new_constraints = [
                parse_requirement("{}!={}".format(bad_meta.name,
                                                  bad_meta.version))
            ]
            bad_constraint = req_compile.containers.DistInfo(
                "#bad#-{}-{}".format(baddest_node, depth),
                parse_version("0.0.0"),
                new_constraints,
                meta=True,
            )
            dists.remove_dists(baddest_node, remove_upstream=False)
            baddest_node.complete = False
            dists.remove_dists(node, remove_upstream=False)
            node.complete = False

            bad_constraints = dists.add_dist(bad_constraint, None, None)
            try:
                logger.debug("Finding new solutions for %s and %s", node,
                             baddest_node)
                for node_to_compile in (node, baddest_node):
                    compile_roots(
                        node_to_compile,
                        None,
                        repo,
                        dists,
                        options,
                        depth=depth,
                        max_downgrade=max_downgrade - 1,
                        _path=_path,
                    )

                print(
                    "Could not use {} {} - pin to this version to see why not".
                    format(bad_meta.name, bad_meta.version),
                    file=sys.stderr,
                )
            finally:
                dists.remove_dists(bad_constraints, remove_upstream=True)
Exemple #3
0
def test_gr():
    assert is_possible(parse_req("thing>1"))
Exemple #4
0
def test_lt():
    assert is_possible(parse_req("thing<1"))
Exemple #5
0
def test_gre_lte_equals():
    assert is_possible(parse_req("thing>=1,<=1,==1"))
Exemple #6
0
def test_not_equals():
    assert is_possible(parse_req("thing!=1"))
    assert is_possible(parse_req("thing!=1,!=2,!=3"))
Exemple #7
0
def test_two_greater():
    assert is_possible(parse_req("thing>1,>2,<3"))
Exemple #8
0
def test_two_greater_equals():
    assert is_possible(parse_req("thing>1,>=2,==2"))
Exemple #9
0
def test_beta_version():
    assert is_possible(parse_req('thing<20b0'))
Exemple #10
0
def test_no_constraints():
    assert is_possible(parse_req("thing"))
Exemple #11
0
def test_dev_version():
    assert not is_possible(parse_req('thing<1.6,<2.0dev,>=1.5,>=1.6.0'))
Exemple #12
0
def test_equals_not_equals():
    assert not is_possible(parse_req("thing==1,!=1"))
Exemple #13
0
def test_greater_equal():
    assert not is_possible(parse_req("thing>1.12,==1.0.2"))
Exemple #14
0
def test_greater_less():
    assert not is_possible(parse_req("thing>1.12,<1"))
Exemple #15
0
def test_two_equals():
    assert not is_possible(parse_req("thing==1,==2"))