Path: blob/main/test/lib/python3.9/site-packages/pip/_internal/commands/show.py
4804 views
import logging1from optparse import Values2from typing import Generator, Iterable, Iterator, List, NamedTuple, Optional34from pip._vendor.packaging.utils import canonicalize_name56from pip._internal.cli.base_command import Command7from pip._internal.cli.status_codes import ERROR, SUCCESS8from pip._internal.metadata import BaseDistribution, get_default_environment9from pip._internal.utils.misc import write_output1011logger = logging.getLogger(__name__)121314class ShowCommand(Command):15"""16Show information about one or more installed packages.1718The output is in RFC-compliant mail header format.19"""2021usage = """22%prog [options] <package> ..."""23ignore_require_venv = True2425def add_options(self) -> None:26self.cmd_opts.add_option(27"-f",28"--files",29dest="files",30action="store_true",31default=False,32help="Show the full list of installed files for each package.",33)3435self.parser.insert_option_group(0, self.cmd_opts)3637def run(self, options: Values, args: List[str]) -> int:38if not args:39logger.warning("ERROR: Please provide a package name or names.")40return ERROR41query = args4243results = search_packages_info(query)44if not print_results(45results, list_files=options.files, verbose=options.verbose46):47return ERROR48return SUCCESS495051class _PackageInfo(NamedTuple):52name: str53version: str54location: str55requires: List[str]56required_by: List[str]57installer: str58metadata_version: str59classifiers: List[str]60summary: str61homepage: str62project_urls: List[str]63author: str64author_email: str65license: str66entry_points: List[str]67files: Optional[List[str]]686970def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None]:71"""72Gather details from installed distributions. Print distribution name,73version, location, and installed files. Installed files requires a74pip generated 'installed-files.txt' in the distributions '.egg-info'75directory.76"""77env = get_default_environment()7879installed = {dist.canonical_name: dist for dist in env.iter_all_distributions()}80query_names = [canonicalize_name(name) for name in query]81missing = sorted(82[name for name, pkg in zip(query, query_names) if pkg not in installed]83)84if missing:85logger.warning("Package(s) not found: %s", ", ".join(missing))8687def _get_requiring_packages(current_dist: BaseDistribution) -> Iterator[str]:88return (89dist.metadata["Name"] or "UNKNOWN"90for dist in installed.values()91if current_dist.canonical_name92in {canonicalize_name(d.name) for d in dist.iter_dependencies()}93)9495for query_name in query_names:96try:97dist = installed[query_name]98except KeyError:99continue100101requires = sorted((req.name for req in dist.iter_dependencies()), key=str.lower)102required_by = sorted(_get_requiring_packages(dist), key=str.lower)103104try:105entry_points_text = dist.read_text("entry_points.txt")106entry_points = entry_points_text.splitlines(keepends=False)107except FileNotFoundError:108entry_points = []109110files_iter = dist.iter_declared_entries()111if files_iter is None:112files: Optional[List[str]] = None113else:114files = sorted(files_iter)115116metadata = dist.metadata117118yield _PackageInfo(119name=dist.raw_name,120version=str(dist.version),121location=dist.location or "",122requires=requires,123required_by=required_by,124installer=dist.installer,125metadata_version=dist.metadata_version or "",126classifiers=metadata.get_all("Classifier", []),127summary=metadata.get("Summary", ""),128homepage=metadata.get("Home-page", ""),129project_urls=metadata.get_all("Project-URL", []),130author=metadata.get("Author", ""),131author_email=metadata.get("Author-email", ""),132license=metadata.get("License", ""),133entry_points=entry_points,134files=files,135)136137138def print_results(139distributions: Iterable[_PackageInfo],140list_files: bool,141verbose: bool,142) -> bool:143"""144Print the information from installed distributions found.145"""146results_printed = False147for i, dist in enumerate(distributions):148results_printed = True149if i > 0:150write_output("---")151152write_output("Name: %s", dist.name)153write_output("Version: %s", dist.version)154write_output("Summary: %s", dist.summary)155write_output("Home-page: %s", dist.homepage)156write_output("Author: %s", dist.author)157write_output("Author-email: %s", dist.author_email)158write_output("License: %s", dist.license)159write_output("Location: %s", dist.location)160write_output("Requires: %s", ", ".join(dist.requires))161write_output("Required-by: %s", ", ".join(dist.required_by))162163if verbose:164write_output("Metadata-Version: %s", dist.metadata_version)165write_output("Installer: %s", dist.installer)166write_output("Classifiers:")167for classifier in dist.classifiers:168write_output(" %s", classifier)169write_output("Entry-points:")170for entry in dist.entry_points:171write_output(" %s", entry.strip())172write_output("Project-URLs:")173for project_url in dist.project_urls:174write_output(" %s", project_url)175if list_files:176write_output("Files:")177if dist.files is None:178write_output("Cannot locate RECORD or installed-files.txt")179else:180for line in dist.files:181write_output(" %s", line.strip())182return results_printed183184185