python (3.11.7)

(root)/
lib/
python3.11/
site-packages/
pip/
_internal/
commands/
show.py
       1  import logging
       2  from optparse import Values
       3  from typing import Generator, Iterable, Iterator, List, NamedTuple, Optional
       4  
       5  from pip._vendor.packaging.utils import canonicalize_name
       6  
       7  from pip._internal.cli.base_command import Command
       8  from pip._internal.cli.status_codes import ERROR, SUCCESS
       9  from pip._internal.metadata import BaseDistribution, get_default_environment
      10  from pip._internal.utils.misc import write_output
      11  
      12  logger = logging.getLogger(__name__)
      13  
      14  
      15  class ESC[4;38;5;81mShowCommand(ESC[4;38;5;149mCommand):
      16      """
      17      Show information about one or more installed packages.
      18  
      19      The output is in RFC-compliant mail header format.
      20      """
      21  
      22      usage = """
      23        %prog [options] <package> ..."""
      24      ignore_require_venv = True
      25  
      26      def add_options(self) -> None:
      27          self.cmd_opts.add_option(
      28              "-f",
      29              "--files",
      30              dest="files",
      31              action="store_true",
      32              default=False,
      33              help="Show the full list of installed files for each package.",
      34          )
      35  
      36          self.parser.insert_option_group(0, self.cmd_opts)
      37  
      38      def run(self, options: Values, args: List[str]) -> int:
      39          if not args:
      40              logger.warning("ERROR: Please provide a package name or names.")
      41              return ERROR
      42          query = args
      43  
      44          results = search_packages_info(query)
      45          if not print_results(
      46              results, list_files=options.files, verbose=options.verbose
      47          ):
      48              return ERROR
      49          return SUCCESS
      50  
      51  
      52  class ESC[4;38;5;81m_PackageInfo(ESC[4;38;5;149mNamedTuple):
      53      name: str
      54      version: str
      55      location: str
      56      editable_project_location: Optional[str]
      57      requires: List[str]
      58      required_by: List[str]
      59      installer: str
      60      metadata_version: str
      61      classifiers: List[str]
      62      summary: str
      63      homepage: str
      64      project_urls: List[str]
      65      author: str
      66      author_email: str
      67      license: str
      68      entry_points: List[str]
      69      files: Optional[List[str]]
      70  
      71  
      72  def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None]:
      73      """
      74      Gather details from installed distributions. Print distribution name,
      75      version, location, and installed files. Installed files requires a
      76      pip generated 'installed-files.txt' in the distributions '.egg-info'
      77      directory.
      78      """
      79      env = get_default_environment()
      80  
      81      installed = {dist.canonical_name: dist for dist in env.iter_all_distributions()}
      82      query_names = [canonicalize_name(name) for name in query]
      83      missing = sorted(
      84          [name for name, pkg in zip(query, query_names) if pkg not in installed]
      85      )
      86      if missing:
      87          logger.warning("Package(s) not found: %s", ", ".join(missing))
      88  
      89      def _get_requiring_packages(current_dist: BaseDistribution) -> Iterator[str]:
      90          return (
      91              dist.metadata["Name"] or "UNKNOWN"
      92              for dist in installed.values()
      93              if current_dist.canonical_name
      94              in {canonicalize_name(d.name) for d in dist.iter_dependencies()}
      95          )
      96  
      97      for query_name in query_names:
      98          try:
      99              dist = installed[query_name]
     100          except KeyError:
     101              continue
     102  
     103          requires = sorted((req.name for req in dist.iter_dependencies()), key=str.lower)
     104          required_by = sorted(_get_requiring_packages(dist), key=str.lower)
     105  
     106          try:
     107              entry_points_text = dist.read_text("entry_points.txt")
     108              entry_points = entry_points_text.splitlines(keepends=False)
     109          except FileNotFoundError:
     110              entry_points = []
     111  
     112          files_iter = dist.iter_declared_entries()
     113          if files_iter is None:
     114              files: Optional[List[str]] = None
     115          else:
     116              files = sorted(files_iter)
     117  
     118          metadata = dist.metadata
     119  
     120          yield _PackageInfo(
     121              name=dist.raw_name,
     122              version=str(dist.version),
     123              location=dist.location or "",
     124              editable_project_location=dist.editable_project_location,
     125              requires=requires,
     126              required_by=required_by,
     127              installer=dist.installer,
     128              metadata_version=dist.metadata_version or "",
     129              classifiers=metadata.get_all("Classifier", []),
     130              summary=metadata.get("Summary", ""),
     131              homepage=metadata.get("Home-page", ""),
     132              project_urls=metadata.get_all("Project-URL", []),
     133              author=metadata.get("Author", ""),
     134              author_email=metadata.get("Author-email", ""),
     135              license=metadata.get("License", ""),
     136              entry_points=entry_points,
     137              files=files,
     138          )
     139  
     140  
     141  def print_results(
     142      distributions: Iterable[_PackageInfo],
     143      list_files: bool,
     144      verbose: bool,
     145  ) -> bool:
     146      """
     147      Print the information from installed distributions found.
     148      """
     149      results_printed = False
     150      for i, dist in enumerate(distributions):
     151          results_printed = True
     152          if i > 0:
     153              write_output("---")
     154  
     155          write_output("Name: %s", dist.name)
     156          write_output("Version: %s", dist.version)
     157          write_output("Summary: %s", dist.summary)
     158          write_output("Home-page: %s", dist.homepage)
     159          write_output("Author: %s", dist.author)
     160          write_output("Author-email: %s", dist.author_email)
     161          write_output("License: %s", dist.license)
     162          write_output("Location: %s", dist.location)
     163          if dist.editable_project_location is not None:
     164              write_output(
     165                  "Editable project location: %s", dist.editable_project_location
     166              )
     167          write_output("Requires: %s", ", ".join(dist.requires))
     168          write_output("Required-by: %s", ", ".join(dist.required_by))
     169  
     170          if verbose:
     171              write_output("Metadata-Version: %s", dist.metadata_version)
     172              write_output("Installer: %s", dist.installer)
     173              write_output("Classifiers:")
     174              for classifier in dist.classifiers:
     175                  write_output("  %s", classifier)
     176              write_output("Entry-points:")
     177              for entry in dist.entry_points:
     178                  write_output("  %s", entry.strip())
     179              write_output("Project-URLs:")
     180              for project_url in dist.project_urls:
     181                  write_output("  %s", project_url)
     182          if list_files:
     183              write_output("Files:")
     184              if dist.files is None:
     185                  write_output("Cannot locate RECORD or installed-files.txt")
     186              else:
     187                  for line in dist.files:
     188                      write_output("  %s", line.strip())
     189      return results_printed