예제 #1
0
    def _iter_interpreters():
        # type: () -> Iterator[InterpreterOrError]
        seen = set()

        normalized_paths = (OrderedSet(
            PythonInterpreter.canonicalize_path(p)
            for p in path.split(os.pathsep)) if path else None)

        # Prefer the current interpreter, if valid.
        current_interpreter = preferred_interpreter or PythonInterpreter.get()
        if not _valid_path or _valid_path(current_interpreter.binary):
            if normalized_paths:
                candidate_paths = frozenset(
                    (current_interpreter.binary,
                     os.path.dirname(current_interpreter.binary)))
                candidate_paths_in_path = candidate_paths.intersection(
                    normalized_paths)
                if candidate_paths_in_path:
                    # In case the full path of the current interpreter binary was in the
                    # `normalized_paths` we're searching, remove it to prevent identifying it again
                    # just to then skip it as `seen`.
                    normalized_paths.discard(current_interpreter.binary)
                    seen.add(current_interpreter)
                    yield current_interpreter
            else:
                seen.add(current_interpreter)
                yield current_interpreter

        for interp in PythonInterpreter.iter_candidates(
                paths=normalized_paths, path_filter=_valid_path):
            if interp not in seen:
                seen.add(interp)
                yield interp
예제 #2
0
    def create_message(self, preamble=None):
        # type: (Optional[str]) -> str
        """Create a message describing  failure to find matching interpreters with an optional
        preamble.

        :param preamble: An optional preamble to the message that will be displayed above it
                             separated by an empty blank line.
        :return: A descriptive message useable for display to an end user.
        """
        preamble = "{}\n\n".format(preamble) if preamble else ""

        failures_message = ""
        if self.failures:
            seen = set()
            broken_interpreters = []
            for python, error in self.failures:
                canonical_python = PythonInterpreter.canonicalize_path(python)
                if canonical_python not in seen:
                    broken_interpreters.append((canonical_python, error))
                    seen.add(canonical_python)

            failures_message = (
                "{}\n"
                "\n"
                "(See https://github.com/pantsbuild/pex/issues/1027 for a list of known breaks and "
                "workarounds.)").format("\n".join(
                    "{index}.) {binary}:\n{error}".format(
                        index=i, binary=python, error=error)
                    for i, (python,
                            error) in enumerate(broken_interpreters, start=1)))

        if not self.candidates:
            if failures_message:
                return (
                    "{preamble}"
                    "Interpreters were found but they all appear to be broken:\n"
                    "{failures}").format(preamble=preamble,
                                         failures=failures_message)
            return "{}No interpreters could be found on the system.".format(
                preamble)

        binary_column_width = max(
            len(candidate.binary) for candidate in self.candidates)
        interpreters_format = "{{index}}.) {{binary: >{}}} {{requirement}}".format(
            binary_column_width)

        qualifier = ""
        if failures_message:
            failures_message = "Skipped the following broken interpreters:\n{}".format(
                failures_message)
            qualifier = "working "

        constraints_message = ""
        if self.constraints:
            constraints_message = (
                "No {qualifier}interpreter compatible with the requested constraints was found:\n"
                "  {constraints}").format(qualifier=qualifier,
                                          constraints="\n  ".join(
                                              self.constraints))

        problems = "\n\n".join(msg for msg in (failures_message,
                                               constraints_message) if msg)
        if problems:
            problems = "\n\n{}".format(problems)

        return (
            "{preamble}"
            "Examined the following {qualifier}interpreters:\n"
            "{interpreters}"
            "{problems}").format(
                preamble=preamble,
                qualifier=qualifier,
                interpreters="\n".join(
                    interpreters_format.format(
                        index=i,
                        binary=candidate.binary,
                        requirement=candidate.identity.requirement)
                    for i, candidate in enumerate(self.candidates, start=1)),
                problems=problems,
            )