Exemple #1
0
def get_benchopt_requirement():
    """Specification for pip requirement to install benchopt in conda env.

    Find out how benchopt was installed so we can install the same version
    even if it was installed in develop mode. This requires pip version >= 20.1

    Returns
    -------
    pip_requirement : str
        String to pass to pip to instal benchopt in another environment.
    is_editable : bool
        Whether the current installation is in development mode or not.
    """
    # Ignore distutils replacement warning when importing pip package. It is
    # not clear why this started to trigger such warning in #265
    # XXX - Investigate this warning and fix it.
    import warnings
    warnings.filterwarnings("ignore",
                            message="Setuptools is replacing distutils.",
                            category=UserWarning)
    from pip._internal.metadata import get_default_environment
    from pip._internal.operations.freeze import FrozenRequirement

    dist = get_default_environment().get_distribution('benchopt')

    # If benchopt is installed in editable mode, get the module path to install
    # it directly from the folder. Else, install it correctly even if it is
    # installed with an url.
    assert dist is not None, (
        'benchopt is not installed in the current environment?')
    req = FrozenRequirement.from_dist(dist)
    if req.editable:
        return f'-e {dist.location}', True

    return str(req), False
Exemple #2
0
    def uninstall(self,
                  auto_confirm: bool = False,
                  verbose: bool = False) -> Optional[UninstallPathSet]:
        """
        Uninstall the distribution currently satisfying this requirement.

        Prompts before removing or modifying files unless
        ``auto_confirm`` is True.

        Refuses to delete or modify files outside of ``sys.prefix`` -
        thus uninstallation within a virtual environment can only
        modify that virtual environment, even if the virtualenv is
        linked to global site-packages.

        """
        assert self.req
        dist = get_default_environment().get_distribution(self.req.name)
        if not dist:
            logger.warning("Skipping %s as it is not installed.", self.name)
            return None
        logger.info("Found existing installation: %s", dist)

        uninstalled_pathset = UninstallPathSet.from_dist(dist)
        uninstalled_pathset.remove(auto_confirm, verbose)
        return uninstalled_pathset
Exemple #3
0
    def get_installed_distributions(
         local_only: bool = True,
         skip: Container[str] = stdlib_pkgs,
         include_editables: bool = True,
         editables_only: bool = False,
         user_only: bool = False,
         paths: Optional[List[str]] = None,
     ) -> List[Distribution]:  # pragma: no cover
        """Return a list of installed Distribution objects.

        Left for compatibility until direct pkg_resources uses are refactored
        out.
        """
        if paths is None:
            env = get_default_environment()
        else:
            env = get_environment(paths)

        dists = env.iter_installed_distributions(
            local_only=local_only,
            skip=skip,
            include_editables=include_editables,
            editables_only=editables_only,
            user_only=user_only,
        )
        return [cast(_Dist, dist)._dist for dist in dists]
Exemple #4
0
 def check_requirements(
         self,
         reqs: Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]]:
     """Return 2 sets:
     - conflicting requirements: set of (installed, wanted) reqs tuples
     - missing requirements: set of reqs
     """
     missing = set()
     conflicting = set()
     if reqs:
         env = (get_environment(self._lib_dirs) if hasattr(
             self, "_lib_dirs") else get_default_environment())
         for req_str in reqs:
             req = Requirement(req_str)
             if req.marker is not None and not req.marker.evaluate():
                 continue  # FIXME: Consider extras?
             dist = env.get_distribution(req.name)
             if not dist:
                 missing.add(req_str)
                 continue
             if isinstance(dist.version, Version):
                 installed_req_str = f"{req.name}=={dist.version}"
             else:
                 installed_req_str = f"{req.name}==={dist.version}"
             if dist.version not in req.specifier:
                 conflicting.add((installed_req_str, req_str))
             # FIXME: Consider direct URL?
     return conflicting, missing
def pip_self_version_check(session: PipSession,
                           options: optparse.Values) -> None:
    """Check for an update for pip.

    Limit the frequency of checks to once per week. State is stored either in
    the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix
    of the pip script path.
    """
    installed_dist = get_default_environment().get_distribution("pip")
    if not installed_dist:
        return

    try:
        upgrade_prompt = _self_version_check_logic(
            state=SelfCheckState(cache_dir=options.cache_dir),
            current_time=datetime.datetime.utcnow(),
            local_version=installed_dist.version,
            get_remote_version=functools.partial(
                _get_current_remote_pip_version, session, options),
        )
        if upgrade_prompt is not None:
            logger.info("[present-rich] %s", upgrade_prompt)
    except Exception:
        logger.warning(
            "There was an error checking the latest version of pip.")
        logger.debug("See below for error", exc_info=True)
Exemple #6
0
 def check_requirements(
     self, reqs: Iterable[str]
 ) -> Tuple[Set[Tuple[str, str]], Set[str]]:
     """Return 2 sets:
     - conflicting requirements: set of (installed, wanted) reqs tuples
     - missing requirements: set of reqs
     """
     missing = set()
     conflicting = set()
     if reqs:
         env = (
             get_environment(self._lib_dirs)
             if hasattr(self, "_lib_dirs")
             else get_default_environment()
         )
         for req_str in reqs:
             req = Requirement(req_str)
             # We're explicitly evaluating with an empty extra value, since build
             # environments are not provided any mechanism to select specific extras.
             if req.marker is not None and not req.marker.evaluate({"extra": ""}):
                 continue
             dist = env.get_distribution(req.name)
             if not dist:
                 missing.add(req_str)
                 continue
             if isinstance(dist.version, Version):
                 installed_req_str = f"{req.name}=={dist.version}"
             else:
                 installed_req_str = f"{req.name}==={dist.version}"
             if not req.specifier.contains(dist.version, prereleases=True):
                 conflicting.add((installed_req_str, req_str))
             # FIXME: Consider direct URL?
     return conflicting, missing
Exemple #7
0
def get_installed_distributions(
        local_only=True,  # type: bool
        skip=stdlib_pkgs,  # type: Container[str]
        include_editables=True,  # type: bool
        editables_only=False,  # type: bool
        user_only=False,  # type: bool
        paths=None  # type: Optional[List[str]]
):
    # type: (...) -> List[Distribution]
    """Return a list of installed Distribution objects.

    Left for compatibility until direct pkg_resources uses are refactored out.
    """
    from pip._internal.metadata import get_default_environment, get_environment
    from pip._internal.metadata.pkg_resources import Distribution as _Dist

    if paths is None:
        env = get_default_environment()
    else:
        env = get_environment(paths)
    dists = env.iter_installed_distributions(
        local_only=local_only,
        skip=skip,
        include_editables=include_editables,
        editables_only=editables_only,
        user_only=user_only,
    )
    return [cast(_Dist, dist)._dist for dist in dists]
Exemple #8
0
def get_benchopt_requirement():
    """Specification for pip requirement to install benchopt in conda env.

    Find out how benchopt where installed so we can install the same version
    even if it was installed in develop mode. This requires pip version >= 20.1

    Returns
    -------
    pip_requirement : str
        String to pass to pip to instal benchopt in another environment.
    is_editable : bool
        Whether the current installation is in development mode or not.
    """
    from pip._internal.metadata import get_default_environment
    from pip._internal.operations.freeze import FrozenRequirement

    dist = get_default_environment().get_distribution('benchopt')

    # If benchopt is installed in editable mode, get the module path to install
    # it directly from the folder. Else, install it correctly even if it is
    # installed with an url.
    assert dist is not None, (
        'benchopt is not installed in the current environment?')
    req = FrozenRequirement.from_dist(dist)
    if req.editable:
        return f'-e {dist.location}', True

    return str(req), False
def was_installed_by_pip(pkg: str) -> bool:
    """Checks whether pkg was installed by pip

    This is used not to display the upgrade message when pip is in fact
    installed by system package manager, such as dnf on Fedora.
    """
    dist = get_default_environment().get_distribution(pkg)
    return dist is not None and "pip" == dist.installer
Exemple #10
0
def get_installed_distributions(local_only=True,
                                skip=None,
                                include_editables=True,
                                editables_only=False,
                                user_only=False,
                                use_cmd=False):
    """
    Directs call to function *get_installed_distributions* from :epkg:`pip`.

    Return a list of installed Distribution objects.

    :param local_only: if True (default), only return installations
        local to the current virtualenv, if in a virtualenv.
    :param skip: argument is an iterable of lower-case project names to
        ignore; defaults to ``pip.compat.stdlib_pkgs`` (if *skip* is None)
    :param editables: if False, don't report editables.
    :param editables_only: if True , only report editables.
    :param user_only: if True , only report installations in the user
        site directory.
    :param use_cmd: if True, use a different process (updated package list)
    :return: list of installed Distribution objects.

    .. versionadded:: 1.5
    """
    if use_cmd:
        raise NotImplementedError("use_cmd should be False")
    if skip is None:
        try:
            from pip._internal.utils.compat import stdlib_pkgs
            skip = stdlib_pkgs
        except ImportError:
            pass
    try:
        from pip._internal.metadata import get_default_environment
        return list(
            map(
                Distribution,
                get_default_environment().iter_installed_distributions(
                    local_only=local_only,
                    skip=skip,
                    include_editables=include_editables,
                    editables_only=editables_only,
                    user_only=user_only)))

    except ImportError:
        from pip._internal.utils.misc import get_installed_distributions as getd
        return list(
            map(
                Distribution,
                getd(local_only=local_only,
                     skip=skip,
                     include_editables=include_editables,
                     editables_only=editables_only,
                     user_only=user_only,
                     use_cmd=use_cmd)))
Exemple #11
0
def print_dist_installation_info(name: str, latest: str) -> None:
    env = get_default_environment()
    dist = env.get_distribution(name)
    if dist is not None:
        with indent_log():
            if dist.version == latest:
                write_output('INSTALLED: %s (latest)', dist.version)
            else:
                write_output('INSTALLED: %s', dist.version)
                if parse_version(latest).pre:
                    write_output('LATEST:    %s (pre-release; install'
                                 ' with "pip install --pre")', latest)
                else:
                    write_output('LATEST:    %s', latest)
Exemple #12
0
def create_package_set_from_installed() -> Tuple[PackageSet, bool]:
    """Converts a list of distributions into a PackageSet."""
    package_set = {}
    problems = False
    env = get_default_environment()
    for dist in env.iter_installed_distributions(local_only=False, skip=()):
        name = dist.canonical_name
        try:
            dependencies = list(dist.iter_dependencies())
            package_set[name] = PackageDetails(dist.version, dependencies)
        except (OSError, ValueError) as e:
            # Don't crash on unreadable or broken metadata.
            logger.warning("Error parsing requirements for %s: %s", name, e)
            problems = True
    return package_set, problems
Exemple #13
0
def get_distribution(req_name):
    # type: (str) -> Optional[Distribution]
    """Given a requirement name, return the installed Distribution object.

    This searches from *all* distributions available in the environment, to
    match the behavior of ``pkg_resources.get_distribution()``.

    Left for compatibility until direct pkg_resources uses are refactored out.
    """
    from pip._internal.metadata import get_default_environment
    from pip._internal.metadata.pkg_resources import Distribution as _Dist
    dist = get_default_environment().get_distribution(req_name)
    if dist is None:
        return None
    return cast(_Dist, dist)._dist
def test_uninstallpathset_no_paths(caplog: pytest.LogCaptureFixture) -> None:
    """
    Test UninstallPathSet logs notification when there are no paths to
    uninstall
    """
    from pip._internal.metadata import get_default_environment
    from pip._internal.req.req_uninstall import UninstallPathSet

    caplog.set_level(logging.INFO)

    test_dist = get_default_environment().get_distribution("pip")
    assert test_dist is not None, "pip not installed"

    uninstall_set = UninstallPathSet(test_dist)
    uninstall_set.remove()  # with no files added to set

    assert "Can't uninstall 'pip'. No files were found to uninstall." in caplog.text
        def get_installed_distributions():
            from pip._internal.metadata import (
                get_default_environment,
                get_environment,
            )
            from pip._internal.metadata.pkg_resources import (
                Distribution as _Dist, )
            from pip._internal.utils.compat import stdlib_pkgs

            env = get_default_environment()
            dists = env.iter_installed_distributions(
                local_only=True,
                skip=stdlib_pkgs,
                include_editables=True,
                editables_only=False,
                user_only=False,
            )
            return [dist._dist for dist in dists]
Exemple #16
0
def print_results(hits, name_column_width=None, terminal_width=None):
    # type: (List[TransformedHit], Optional[int], Optional[int]) -> None
    if not hits:
        return
    if name_column_width is None:
        name_column_width = max([
            len(hit['name']) + len(highest_version(hit.get('versions', ['-'])))
            for hit in hits
        ]) + 4

    env = get_default_environment()
    for hit in hits:
        name = hit['name']
        summary = hit['summary'] or ''
        latest = highest_version(hit.get('versions', ['-']))
        if terminal_width is not None:
            target_width = terminal_width - name_column_width - 5
            if target_width > 10:
                # wrap and indent summary to fit terminal
                summary_lines = textwrap.wrap(summary, target_width)
                summary = ('\n' + ' ' *
                           (name_column_width + 3)).join(summary_lines)

        line = '{name_latest:{name_column_width}} - {summary}'.format(
            name_latest='{name} ({latest})'.format(**locals()), **locals())
        try:
            write_output(line)
            dist = env.get_distribution(name)
            if dist is not None:
                with indent_log():
                    if dist.version == latest:
                        write_output('INSTALLED: %s (latest)', dist.version)
                    else:
                        write_output('INSTALLED: %s', dist.version)
                        if parse_version(latest).pre:
                            write_output(
                                'LATEST:    %s (pre-release; install'
                                ' with "pip install --pre")', latest)
                        else:
                            write_output('LATEST:    %s', latest)
        except UnicodeEncodeError:
            pass
Exemple #17
0
 def get_installed_distributions(
     local_only = True,
     skip = stdlib_pkgs,
     include_editables = True,
     editables_only = False,
     user_only = False,
     paths = None,
 ):
     if paths is None:
         env = get_default_environment()
     else:
         env = get_environment(paths)
     dists = env.iter_installed_distributions(
         local_only=local_only,
         skip=skip,
         include_editables=include_editables,
         editables_only=editables_only,
         user_only=user_only,
     )
     return dists
Exemple #18
0
    def __init__(
        self,
        finder: PackageFinder,
        preparer: RequirementPreparer,
        make_install_req: InstallRequirementProvider,
        wheel_cache: Optional[WheelCache],
        use_user_site: bool,
        force_reinstall: bool,
        ignore_installed: bool,
        ignore_requires_python: bool,
        suppress_build_failures: bool,
        py_version_info: Optional[Tuple[int, ...]] = None,
    ) -> None:
        self._finder = finder
        self.preparer = preparer
        self._wheel_cache = wheel_cache
        self._python_candidate = RequiresPythonCandidate(py_version_info)
        self._make_install_req_from_spec = make_install_req
        self._use_user_site = use_user_site
        self._force_reinstall = force_reinstall
        self._ignore_requires_python = ignore_requires_python
        self._suppress_build_failures = suppress_build_failures

        self._build_failures: Cache[InstallationError] = {}
        self._link_candidate_cache: Cache[LinkCandidate] = {}
        self._editable_candidate_cache: Cache[EditableCandidate] = {}
        self._installed_candidate_cache: Dict[str,
                                              AlreadyInstalledCandidate] = {}
        self._extras_candidate_cache: Dict[Tuple[int, FrozenSet[str]],
                                           ExtrasCandidate] = {}

        if not ignore_installed:
            env = get_default_environment()
            self._installed_dists = {
                dist.canonical_name: dist
                for dist in env.iter_installed_distributions(local_only=False)
            }
        else:
            self._installed_dists = {}
Exemple #19
0
    def check_if_exists(self, use_user_site: bool) -> None:
        """Find an installed distribution that satisfies or conflicts
        with this requirement, and set self.satisfied_by or
        self.should_reinstall appropriately.
        """
        if self.req is None:
            return
        existing_dist = get_default_environment().get_distribution(
            self.req.name)
        if not existing_dist:
            return

        version_compatible = self.req.specifier.contains(
            existing_dist.version,
            prereleases=True,
        )
        if not version_compatible:
            self.satisfied_by = None
            if use_user_site:
                if existing_dist.in_usersite:
                    self.should_reinstall = True
                elif running_under_virtualenv(
                ) and existing_dist.in_site_packages:
                    raise InstallationError(
                        f"Will not install to the user site because it will "
                        f"lack sys.path precedence to {existing_dist.raw_name} "
                        f"in {existing_dist.location}")
            else:
                self.should_reinstall = True
        else:
            if self.editable:
                self.should_reinstall = True
                # when installing editables, nothing pre-existing should ever
                # satisfy
                self.satisfied_by = None
            else:
                self.satisfied_by = existing_dist
Exemple #20
0
        def get_installed_distributions(
            local_only=True,
            include_editables=True,
            editables_only=False,
            user_only=False,
            paths=None,
        ):
            """Return a list of installed Distribution objects.
            Left for compatibility until direct pkg_resources uses are refactored out.
            """
            from pip._internal.metadata import get_default_environment, get_environment
            from pip._internal.metadata.pkg_resources import Distribution as _Dist

            if paths is None:
                env = get_default_environment()
            else:
                env = get_environment(paths)
            dists = env.iter_installed_distributions(
                local_only=local_only,
                include_editables=include_editables,
                editables_only=editables_only,
                user_only=user_only,
            )
            return [cast(_Dist, dist)._dist for dist in dists]
Exemple #21
0
def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]:
    """
    Gather details from installed distributions. Print distribution name,
    version, location, and installed files. Installed files requires a
    pip generated 'installed-files.txt' in the distributions '.egg-info'
    directory.
    """
    env = get_default_environment()

    installed = {dist.canonical_name: dist for dist in env.iter_distributions()}
    query_names = [canonicalize_name(name) for name in query]
    missing = sorted(
        [name for name, pkg in zip(query, query_names) if pkg not in installed]
    )
    if missing:
        logger.warning("Package(s) not found: %s", ", ".join(missing))

    def _get_requiring_packages(current_dist: BaseDistribution) -> Iterator[str]:
        return (
            dist.metadata["Name"] or "UNKNOWN"
            for dist in installed.values()
            if current_dist.canonical_name
            in {canonicalize_name(d.name) for d in dist.iter_dependencies()}
        )

    for query_name in query_names:
        try:
            dist = installed[query_name]
        except KeyError:
            continue

        requires = sorted((req.name for req in dist.iter_dependencies()), key=str.lower)
        required_by = sorted(_get_requiring_packages(dist), key=str.lower)

        try:
            entry_points_text = dist.read_text("entry_points.txt")
            entry_points = entry_points_text.splitlines(keepends=False)
        except FileNotFoundError:
            entry_points = []

        files_iter = dist.iter_declared_entries()
        if files_iter is None:
            files: Optional[List[str]] = None
        else:
            files = sorted(files_iter)

        metadata = dist.metadata

        yield _PackageInfo(
            name=dist.raw_name,
            version=str(dist.version),
            location=dist.location or "",
            requires=requires,
            required_by=required_by,
            installer=dist.installer,
            metadata_version=dist.metadata_version or "",
            classifiers=metadata.get_all("Classifier", []),
            summary=metadata.get("Summary", ""),
            homepage=metadata.get("Home-page", ""),
            author=metadata.get("Author", ""),
            author_email=metadata.get("Author-email", ""),
            license=metadata.get("License", ""),
            entry_points=entry_points,
            files=files,
        )
Exemple #22
0
def autocomplete() -> None:
    """Entry Point for completion of main and subcommand options."""
    # Don't complete if user hasn't sourced bash_completion file.
    if "PIP_AUTO_COMPLETE" not in os.environ:
        return
    cwords = os.environ["COMP_WORDS"].split()[1:]
    cword = int(os.environ["COMP_CWORD"])
    try:
        current = cwords[cword - 1]
    except IndexError:
        current = ""

    parser = create_main_parser()
    subcommands = list(commands_dict)
    options = []

    # subcommand
    subcommand_name: Optional[str] = None
    for word in cwords:
        if word in subcommands:
            subcommand_name = word
            break
    # subcommand options
    if subcommand_name is not None:
        # special case: 'help' subcommand has no options
        if subcommand_name == "help":
            sys.exit(1)
        # special case: list locally installed dists for show and uninstall
        should_list_installed = not current.startswith(
            "-") and subcommand_name in [
                "show",
                "uninstall",
            ]
        if should_list_installed:
            env = get_default_environment()
            lc = current.lower()
            installed = [
                dist.canonical_name
                for dist in env.iter_installed_distributions(local_only=True)
                if dist.canonical_name.startswith(lc)
                and dist.canonical_name not in cwords[1:]
            ]
            # if there are no dists installed, fall back to option completion
            if installed:
                for dist in installed:
                    print(dist)
                sys.exit(1)

        should_list_installables = (not current.startswith("-")
                                    and subcommand_name == "install")
        if should_list_installables:
            for path in auto_complete_paths(current, "path"):
                print(path)
            sys.exit(1)

        subcommand = create_command(subcommand_name)

        for opt in subcommand.parser.option_list_all:
            if opt.help != optparse.SUPPRESS_HELP:
                for opt_str in opt._long_opts + opt._short_opts:
                    options.append((opt_str, opt.nargs))

        # filter out previously specified options from available options
        prev_opts = [x.split("=")[0] for x in cwords[1:cword - 1]]
        options = [(x, v) for (x, v) in options if x not in prev_opts]
        # filter options by current input
        options = [(k, v) for k, v in options if k.startswith(current)]
        # get completion type given cwords and available subcommand options
        completion_type = get_path_completion_type(
            cwords,
            cword,
            subcommand.parser.option_list_all,
        )
        # get completion files and directories if ``completion_type`` is
        # ``<file>``, ``<dir>`` or ``<path>``
        if completion_type:
            paths = auto_complete_paths(current, completion_type)
            options = [(path, 0) for path in paths]
        for option in options:
            opt_label = option[0]
            # append '=' to options which require args
            if option[1] and option[0][:2] == "--":
                opt_label += "="
            print(opt_label)
    else:
        # show main parser options only when necessary

        opts = [i.option_list for i in parser.option_groups]
        opts.append(parser.option_list)
        flattened_opts = chain.from_iterable(opts)
        if current.startswith("-"):
            for opt in flattened_opts:
                if opt.help != optparse.SUPPRESS_HELP:
                    subcommands += opt._long_opts + opt._short_opts
        else:
            # get completion type given cwords and all available options
            completion_type = get_path_completion_type(cwords, cword,
                                                       flattened_opts)
            if completion_type:
                subcommands = list(
                    auto_complete_paths(current, completion_type))

        print(" ".join([x for x in subcommands if x.startswith(current)]))
    sys.exit(1)
Exemple #23
0
def user_agent() -> str:
    """
    Return a string representing the user agent.
    """
    data: Dict[str, Any] = {
        "installer": {"name": "pip", "version": __version__},
        "python": platform.python_version(),
        "implementation": {
            "name": platform.python_implementation(),
        },
    }

    if data["implementation"]["name"] == "CPython":
        data["implementation"]["version"] = platform.python_version()
    elif data["implementation"]["name"] == "PyPy":
        pypy_version_info = sys.pypy_version_info  # type: ignore
        if pypy_version_info.releaselevel == "final":
            pypy_version_info = pypy_version_info[:3]
        data["implementation"]["version"] = ".".join(
            [str(x) for x in pypy_version_info]
        )
    elif data["implementation"]["name"] == "Jython":
        # Complete Guess
        data["implementation"]["version"] = platform.python_version()
    elif data["implementation"]["name"] == "IronPython":
        # Complete Guess
        data["implementation"]["version"] = platform.python_version()

    if sys.platform.startswith("linux"):
        from pip._vendor import distro

        # https://github.com/nir0s/distro/pull/269
        linux_distribution = distro.linux_distribution()  # type: ignore
        distro_infos = dict(
            filter(
                lambda x: x[1],
                zip(["name", "version", "id"], linux_distribution),
            )
        )
        libc = dict(
            filter(
                lambda x: x[1],
                zip(["lib", "version"], libc_ver()),
            )
        )
        if libc:
            distro_infos["libc"] = libc
        if distro_infos:
            data["distro"] = distro_infos

    if sys.platform.startswith("darwin") and platform.mac_ver()[0]:
        data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]}

    if platform.system():
        data.setdefault("system", {})["name"] = platform.system()

    if platform.release():
        data.setdefault("system", {})["release"] = platform.release()

    if platform.machine():
        data["cpu"] = platform.machine()

    if has_tls():
        import _ssl as ssl

        data["openssl_version"] = ssl.OPENSSL_VERSION

    setuptools_dist = get_default_environment().get_distribution("setuptools")
    if setuptools_dist is not None:
        data["setuptools_version"] = str(setuptools_dist.version)

    if shutil.which("rustc") is not None:
        # If for any reason `rustc --version` fails, silently ignore it
        try:
            rustc_output = subprocess.check_output(
                ["rustc", "--version"], stderr=subprocess.STDOUT, timeout=0.5
            )
        except Exception:
            pass
        else:
            if rustc_output.startswith(b"rustc "):
                # The format of `rustc --version` is:
                # `b'rustc 1.52.1 (9bc8c42bb 2021-05-09)\n'`
                # We extract just the middle (1.52.1) part
                data["rustc_version"] = rustc_output.split(b" ")[1].decode()

    # Use None rather than False so as not to give the impression that
    # pip knows it is not being run under CI.  Rather, it is a null or
    # inconclusive result.  Also, we include some value rather than no
    # value to make it easier to know that the check has been run.
    data["ci"] = True if looks_like_ci() else None

    user_data = os.environ.get("PIP_USER_AGENT_USER_DATA")
    if user_data is not None:
        data["user_data"] = user_data

    return "{data[installer][name]}/{data[installer][version]} {json}".format(
        data=data,
        json=json.dumps(data, separators=(",", ":"), sort_keys=True),
    )
Exemple #24
0
def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]:
    """
    Gather details from installed distributions. Print distribution name,
    version, location, and installed files. Installed files requires a
    pip generated 'installed-files.txt' in the distributions '.egg-info'
    directory.
    """
    env = get_default_environment()

    installed = {
        dist.canonical_name: dist
        for dist in env.iter_distributions()
    }
    query_names = [canonicalize_name(name) for name in query]
    missing = sorted([
        name for name, pkg in zip(query, query_names) if pkg not in installed
    ])
    if missing:
        logger.warning('Package(s) not found: %s', ', '.join(missing))

    def _get_requiring_packages(current_dist: BaseDistribution) -> List[str]:
        return [
            dist.metadata["Name"] or "UNKNOWN" for dist in installed.values()
            if current_dist.canonical_name in
            {canonicalize_name(d.name)
             for d in dist.iter_dependencies()}
        ]

    def _files_from_record(dist: BaseDistribution) -> Optional[Iterator[str]]:
        try:
            text = dist.read_text('RECORD')
        except FileNotFoundError:
            return None
        # This extra Path-str cast normalizes entries.
        return (str(pathlib.Path(row[0]))
                for row in csv.reader(text.splitlines()))

    def _files_from_legacy(dist: BaseDistribution) -> Optional[Iterator[str]]:
        try:
            text = dist.read_text('installed-files.txt')
        except FileNotFoundError:
            return None
        paths = (p for p in text.splitlines(keepends=False) if p)
        root = dist.location
        info = dist.info_directory
        if root is None or info is None:
            return paths
        try:
            info_rel = pathlib.Path(info).relative_to(root)
        except ValueError:  # info is not relative to root.
            return paths
        if not info_rel.parts:  # info *is* root.
            return paths
        return (_covert_legacy_entry(pathlib.Path(p).parts, info_rel.parts)
                for p in paths)

    for query_name in query_names:
        try:
            dist = installed[query_name]
        except KeyError:
            continue

        try:
            entry_points_text = dist.read_text('entry_points.txt')
            entry_points = entry_points_text.splitlines(keepends=False)
        except FileNotFoundError:
            entry_points = []

        files_iter = _files_from_record(dist) or _files_from_legacy(dist)
        if files_iter is None:
            files: Optional[List[str]] = None
        else:
            files = sorted(files_iter)

        metadata = dist.metadata

        yield _PackageInfo(
            name=dist.raw_name,
            version=str(dist.version),
            location=dist.location or "",
            requires=[req.name for req in dist.iter_dependencies()],
            required_by=_get_requiring_packages(dist),
            installer=dist.installer,
            metadata_version=dist.metadata_version or "",
            classifiers=metadata.get_all("Classifier", []),
            summary=metadata.get("Summary", ""),
            homepage=metadata.get("Home-page", ""),
            author=metadata.get("Author", ""),
            author_email=metadata.get("Author-email", ""),
            license=metadata.get("License", ""),
            entry_points=entry_points,
            files=files,
        )
Exemple #25
0
def pip_self_version_check(session, options):
    # type: (PipSession, optparse.Values) -> None
    """Check for an update for pip.

    Limit the frequency of checks to once per week. State is stored either in
    the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix
    of the pip script path.
    """
    installed_dist = get_default_environment().get_distribution("pip")
    if not installed_dist:
        return

    pip_version = installed_dist.version
    pypi_version = None

    try:
        state = SelfCheckState(cache_dir=options.cache_dir)

        current_time = datetime.datetime.utcnow()
        # Determine if we need to refresh the state
        if "last_check" in state.state and "pypi_version" in state.state:
            last_check = datetime.datetime.strptime(state.state["last_check"],
                                                    SELFCHECK_DATE_FMT)
            if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60:
                pypi_version = state.state["pypi_version"]

        # Refresh the version if we need to or just see if we need to warn
        if pypi_version is None:
            # Lets use PackageFinder to see what the latest pip version is
            link_collector = LinkCollector.create(
                session,
                options=options,
                suppress_no_index=True,
            )

            # Pass allow_yanked=False so we don't suggest upgrading to a
            # yanked version.
            selection_prefs = SelectionPreferences(
                allow_yanked=False,
                allow_all_prereleases=False,  # Explicitly set to False
            )

            finder = PackageFinder.create(
                link_collector=link_collector,
                selection_prefs=selection_prefs,
            )
            best_candidate = finder.find_best_candidate("pip").best_candidate
            if best_candidate is None:
                return
            pypi_version = str(best_candidate.version)

            # save that we've performed a check
            state.save(pypi_version, current_time)

        remote_version = parse_version(pypi_version)

        local_version_is_older = (
            pip_version < remote_version
            and pip_version.base_version != remote_version.base_version
            and was_installed_by_pip('pip'))

        # Determine if our pypi_version is older
        if not local_version_is_older:
            return

        # We cannot tell how the current pip is available in the current
        # command context, so be pragmatic here and suggest the command
        # that's always available. This does not accommodate spaces in
        # `sys.executable`.
        pip_cmd = f"{sys.executable} -m pip"
        logger.warning(
            "You are using pip version %s; however, version %s is "
            "available.\nYou should consider upgrading via the "
            "'%s install --upgrade pip' command.", pip_version, pypi_version,
            pip_cmd)
    except Exception:
        logger.debug(
            "There was an error checking the latest version of pip",
            exc_info=True,
        )
Exemple #26
0
def user_agent():
    """
    Return a string representing the user agent.
    """
    data = {
        "installer": {
            "name": "pip",
            "version": __version__
        },
        "python": platform.python_version(),
        "implementation": {
            "name": platform.python_implementation(),
        },
    }

    if data["implementation"]["name"] == 'CPython':
        data["implementation"]["version"] = platform.python_version()
    elif data["implementation"]["name"] == 'PyPy':
        if sys.pypy_version_info.releaselevel == 'final':
            pypy_version_info = sys.pypy_version_info[:3]
        else:
            pypy_version_info = sys.pypy_version_info
        data["implementation"]["version"] = ".".join(
            [str(x) for x in pypy_version_info])
    elif data["implementation"]["name"] == 'Jython':
        # Complete Guess
        data["implementation"]["version"] = platform.python_version()
    elif data["implementation"]["name"] == 'IronPython':
        # Complete Guess
        data["implementation"]["version"] = platform.python_version()

    if sys.platform.startswith("linux"):
        from pip._vendor import distro
        distro_infos = dict(
            filter(
                lambda x: x[1],
                zip(["name", "version", "id"], distro.linux_distribution()),
            ))
        libc = dict(
            filter(
                lambda x: x[1],
                zip(["lib", "version"], libc_ver()),
            ))
        if libc:
            distro_infos["libc"] = libc
        if distro_infos:
            data["distro"] = distro_infos

    if sys.platform.startswith("darwin") and platform.mac_ver()[0]:
        data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]}

    if platform.system():
        data.setdefault("system", {})["name"] = platform.system()

    if platform.release():
        data.setdefault("system", {})["release"] = platform.release()

    if platform.machine():
        data["cpu"] = platform.machine()

    if has_tls():
        import _ssl as ssl
        data["openssl_version"] = ssl.OPENSSL_VERSION

    setuptools_dist = get_default_environment().get_distribution("setuptools")
    if setuptools_dist is not None:
        data["setuptools_version"] = str(setuptools_dist.version)

    # Use None rather than False so as not to give the impression that
    # pip knows it is not being run under CI.  Rather, it is a null or
    # inconclusive result.  Also, we include some value rather than no
    # value to make it easier to know that the check has been run.
    data["ci"] = True if looks_like_ci() else None

    user_data = os.environ.get("PIP_USER_AGENT_USER_DATA")
    if user_data is not None:
        data["user_data"] = user_data

    return "{data[installer][name]}/{data[installer][version]} {json}".format(
        data=data,
        json=json.dumps(data, separators=(",", ":"), sort_keys=True),
    )