comparison env/lib/python3.9/site-packages/pip/_internal/commands/show.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 import logging
2 import os
3 from email.parser import FeedParser
4
5 from pip._vendor import pkg_resources
6 from pip._vendor.packaging.utils import canonicalize_name
7
8 from pip._internal.cli.base_command import Command
9 from pip._internal.cli.status_codes import ERROR, SUCCESS
10 from pip._internal.utils.misc import write_output
11 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
12
13 if MYPY_CHECK_RUNNING:
14 from optparse import Values
15 from typing import Dict, Iterator, List
16
17 logger = logging.getLogger(__name__)
18
19
20 class ShowCommand(Command):
21 """
22 Show information about one or more installed packages.
23
24 The output is in RFC-compliant mail header format.
25 """
26
27 usage = """
28 %prog [options] <package> ..."""
29 ignore_require_venv = True
30
31 def add_options(self):
32 # type: () -> None
33 self.cmd_opts.add_option(
34 '-f', '--files',
35 dest='files',
36 action='store_true',
37 default=False,
38 help='Show the full list of installed files for each package.')
39
40 self.parser.insert_option_group(0, self.cmd_opts)
41
42 def run(self, options, args):
43 # type: (Values, List[str]) -> int
44 if not args:
45 logger.warning('ERROR: Please provide a package name or names.')
46 return ERROR
47 query = args
48
49 results = search_packages_info(query)
50 if not print_results(
51 results, list_files=options.files, verbose=options.verbose):
52 return ERROR
53 return SUCCESS
54
55
56 def search_packages_info(query):
57 # type: (List[str]) -> Iterator[Dict[str, str]]
58 """
59 Gather details from installed distributions. Print distribution name,
60 version, location, and installed files. Installed files requires a
61 pip generated 'installed-files.txt' in the distributions '.egg-info'
62 directory.
63 """
64 installed = {}
65 for p in pkg_resources.working_set:
66 installed[canonicalize_name(p.project_name)] = p
67
68 query_names = [canonicalize_name(name) for name in query]
69 missing = sorted(
70 [name for name, pkg in zip(query, query_names) if pkg not in installed]
71 )
72 if missing:
73 logger.warning('Package(s) not found: %s', ', '.join(missing))
74
75 def get_requiring_packages(package_name):
76 # type: (str) -> List[str]
77 canonical_name = canonicalize_name(package_name)
78 return [
79 pkg.project_name for pkg in pkg_resources.working_set
80 if canonical_name in
81 [canonicalize_name(required.name) for required in
82 pkg.requires()]
83 ]
84
85 for dist in [installed[pkg] for pkg in query_names if pkg in installed]:
86 package = {
87 'name': dist.project_name,
88 'version': dist.version,
89 'location': dist.location,
90 'requires': [dep.project_name for dep in dist.requires()],
91 'required_by': get_requiring_packages(dist.project_name)
92 }
93 file_list = None
94 metadata = ''
95 if isinstance(dist, pkg_resources.DistInfoDistribution):
96 # RECORDs should be part of .dist-info metadatas
97 if dist.has_metadata('RECORD'):
98 lines = dist.get_metadata_lines('RECORD')
99 paths = [line.split(',')[0] for line in lines]
100 paths = [os.path.join(dist.location, p) for p in paths]
101 file_list = [os.path.relpath(p, dist.location) for p in paths]
102
103 if dist.has_metadata('METADATA'):
104 metadata = dist.get_metadata('METADATA')
105 else:
106 # Otherwise use pip's log for .egg-info's
107 if dist.has_metadata('installed-files.txt'):
108 paths = dist.get_metadata_lines('installed-files.txt')
109 paths = [os.path.join(dist.egg_info, p) for p in paths]
110 file_list = [os.path.relpath(p, dist.location) for p in paths]
111
112 if dist.has_metadata('PKG-INFO'):
113 metadata = dist.get_metadata('PKG-INFO')
114
115 if dist.has_metadata('entry_points.txt'):
116 entry_points = dist.get_metadata_lines('entry_points.txt')
117 package['entry_points'] = entry_points
118
119 if dist.has_metadata('INSTALLER'):
120 for line in dist.get_metadata_lines('INSTALLER'):
121 if line.strip():
122 package['installer'] = line.strip()
123 break
124
125 # @todo: Should pkg_resources.Distribution have a
126 # `get_pkg_info` method?
127 feed_parser = FeedParser()
128 feed_parser.feed(metadata)
129 pkg_info_dict = feed_parser.close()
130 for key in ('metadata-version', 'summary',
131 'home-page', 'author', 'author-email', 'license'):
132 package[key] = pkg_info_dict.get(key)
133
134 # It looks like FeedParser cannot deal with repeated headers
135 classifiers = []
136 for line in metadata.splitlines():
137 if line.startswith('Classifier: '):
138 classifiers.append(line[len('Classifier: '):])
139 package['classifiers'] = classifiers
140
141 if file_list:
142 package['files'] = sorted(file_list)
143 yield package
144
145
146 def print_results(distributions, list_files=False, verbose=False):
147 # type: (Iterator[Dict[str, str]], bool, bool) -> bool
148 """
149 Print the information from installed distributions found.
150 """
151 results_printed = False
152 for i, dist in enumerate(distributions):
153 results_printed = True
154 if i > 0:
155 write_output("---")
156
157 write_output("Name: %s", dist.get('name', ''))
158 write_output("Version: %s", dist.get('version', ''))
159 write_output("Summary: %s", dist.get('summary', ''))
160 write_output("Home-page: %s", dist.get('home-page', ''))
161 write_output("Author: %s", dist.get('author', ''))
162 write_output("Author-email: %s", dist.get('author-email', ''))
163 write_output("License: %s", dist.get('license', ''))
164 write_output("Location: %s", dist.get('location', ''))
165 write_output("Requires: %s", ', '.join(dist.get('requires', [])))
166 write_output("Required-by: %s", ', '.join(dist.get('required_by', [])))
167
168 if verbose:
169 write_output("Metadata-Version: %s",
170 dist.get('metadata-version', ''))
171 write_output("Installer: %s", dist.get('installer', ''))
172 write_output("Classifiers:")
173 for classifier in dist.get('classifiers', []):
174 write_output(" %s", classifier)
175 write_output("Entry-points:")
176 for entry in dist.get('entry_points', []):
177 write_output(" %s", entry.strip())
178 if list_files:
179 write_output("Files:")
180 for line in dist.get('files', []):
181 write_output(" %s", line.strip())
182 if "files" not in dist:
183 write_output("Cannot locate installed-files.txt")
184 return results_printed