]> jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/pip/_internal/commands/show.py
init: venv aand flask
[dlqueue.git] / venv / 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 ShowCommand(Command):
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 _PackageInfo(NamedTuple):
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