Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/pip/_internal/commands/list.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 json | |
2 import logging | |
3 | |
4 from pip._internal.cli import cmdoptions | |
5 from pip._internal.cli.req_command import IndexGroupCommand | |
6 from pip._internal.cli.status_codes import SUCCESS | |
7 from pip._internal.exceptions import CommandError | |
8 from pip._internal.index.collector import LinkCollector | |
9 from pip._internal.index.package_finder import PackageFinder | |
10 from pip._internal.models.selection_prefs import SelectionPreferences | |
11 from pip._internal.utils.compat import stdlib_pkgs | |
12 from pip._internal.utils.misc import ( | |
13 dist_is_editable, | |
14 get_installed_distributions, | |
15 tabulate, | |
16 write_output, | |
17 ) | |
18 from pip._internal.utils.packaging import get_installer | |
19 from pip._internal.utils.parallel import map_multithread | |
20 from pip._internal.utils.typing import MYPY_CHECK_RUNNING | |
21 | |
22 if MYPY_CHECK_RUNNING: | |
23 from optparse import Values | |
24 from typing import Iterator, List, Set, Tuple | |
25 | |
26 from pip._vendor.pkg_resources import Distribution | |
27 | |
28 from pip._internal.network.session import PipSession | |
29 | |
30 logger = logging.getLogger(__name__) | |
31 | |
32 | |
33 class ListCommand(IndexGroupCommand): | |
34 """ | |
35 List installed packages, including editables. | |
36 | |
37 Packages are listed in a case-insensitive sorted order. | |
38 """ | |
39 | |
40 ignore_require_venv = True | |
41 usage = """ | |
42 %prog [options]""" | |
43 | |
44 def add_options(self): | |
45 # type: () -> None | |
46 self.cmd_opts.add_option( | |
47 '-o', '--outdated', | |
48 action='store_true', | |
49 default=False, | |
50 help='List outdated packages') | |
51 self.cmd_opts.add_option( | |
52 '-u', '--uptodate', | |
53 action='store_true', | |
54 default=False, | |
55 help='List uptodate packages') | |
56 self.cmd_opts.add_option( | |
57 '-e', '--editable', | |
58 action='store_true', | |
59 default=False, | |
60 help='List editable projects.') | |
61 self.cmd_opts.add_option( | |
62 '-l', '--local', | |
63 action='store_true', | |
64 default=False, | |
65 help=('If in a virtualenv that has global access, do not list ' | |
66 'globally-installed packages.'), | |
67 ) | |
68 self.cmd_opts.add_option( | |
69 '--user', | |
70 dest='user', | |
71 action='store_true', | |
72 default=False, | |
73 help='Only output packages installed in user-site.') | |
74 self.cmd_opts.add_option(cmdoptions.list_path()) | |
75 self.cmd_opts.add_option( | |
76 '--pre', | |
77 action='store_true', | |
78 default=False, | |
79 help=("Include pre-release and development versions. By default, " | |
80 "pip only finds stable versions."), | |
81 ) | |
82 | |
83 self.cmd_opts.add_option( | |
84 '--format', | |
85 action='store', | |
86 dest='list_format', | |
87 default="columns", | |
88 choices=('columns', 'freeze', 'json'), | |
89 help="Select the output format among: columns (default), freeze, " | |
90 "or json", | |
91 ) | |
92 | |
93 self.cmd_opts.add_option( | |
94 '--not-required', | |
95 action='store_true', | |
96 dest='not_required', | |
97 help="List packages that are not dependencies of " | |
98 "installed packages.", | |
99 ) | |
100 | |
101 self.cmd_opts.add_option( | |
102 '--exclude-editable', | |
103 action='store_false', | |
104 dest='include_editable', | |
105 help='Exclude editable package from output.', | |
106 ) | |
107 self.cmd_opts.add_option( | |
108 '--include-editable', | |
109 action='store_true', | |
110 dest='include_editable', | |
111 help='Include editable package from output.', | |
112 default=True, | |
113 ) | |
114 self.cmd_opts.add_option(cmdoptions.list_exclude()) | |
115 index_opts = cmdoptions.make_option_group( | |
116 cmdoptions.index_group, self.parser | |
117 ) | |
118 | |
119 self.parser.insert_option_group(0, index_opts) | |
120 self.parser.insert_option_group(0, self.cmd_opts) | |
121 | |
122 def _build_package_finder(self, options, session): | |
123 # type: (Values, PipSession) -> PackageFinder | |
124 """ | |
125 Create a package finder appropriate to this list command. | |
126 """ | |
127 link_collector = LinkCollector.create(session, options=options) | |
128 | |
129 # Pass allow_yanked=False to ignore yanked versions. | |
130 selection_prefs = SelectionPreferences( | |
131 allow_yanked=False, | |
132 allow_all_prereleases=options.pre, | |
133 ) | |
134 | |
135 return PackageFinder.create( | |
136 link_collector=link_collector, | |
137 selection_prefs=selection_prefs, | |
138 ) | |
139 | |
140 def run(self, options, args): | |
141 # type: (Values, List[str]) -> int | |
142 if options.outdated and options.uptodate: | |
143 raise CommandError( | |
144 "Options --outdated and --uptodate cannot be combined.") | |
145 | |
146 cmdoptions.check_list_path_option(options) | |
147 | |
148 skip = set(stdlib_pkgs) | |
149 if options.excludes: | |
150 skip.update(options.excludes) | |
151 | |
152 packages = get_installed_distributions( | |
153 local_only=options.local, | |
154 user_only=options.user, | |
155 editables_only=options.editable, | |
156 include_editables=options.include_editable, | |
157 paths=options.path, | |
158 skip=skip, | |
159 ) | |
160 | |
161 # get_not_required must be called firstly in order to find and | |
162 # filter out all dependencies correctly. Otherwise a package | |
163 # can't be identified as requirement because some parent packages | |
164 # could be filtered out before. | |
165 if options.not_required: | |
166 packages = self.get_not_required(packages, options) | |
167 | |
168 if options.outdated: | |
169 packages = self.get_outdated(packages, options) | |
170 elif options.uptodate: | |
171 packages = self.get_uptodate(packages, options) | |
172 | |
173 self.output_package_listing(packages, options) | |
174 return SUCCESS | |
175 | |
176 def get_outdated(self, packages, options): | |
177 # type: (List[Distribution], Values) -> List[Distribution] | |
178 return [ | |
179 dist for dist in self.iter_packages_latest_infos(packages, options) | |
180 if dist.latest_version > dist.parsed_version | |
181 ] | |
182 | |
183 def get_uptodate(self, packages, options): | |
184 # type: (List[Distribution], Values) -> List[Distribution] | |
185 return [ | |
186 dist for dist in self.iter_packages_latest_infos(packages, options) | |
187 if dist.latest_version == dist.parsed_version | |
188 ] | |
189 | |
190 def get_not_required(self, packages, options): | |
191 # type: (List[Distribution], Values) -> List[Distribution] | |
192 dep_keys = set() # type: Set[Distribution] | |
193 for dist in packages: | |
194 dep_keys.update(requirement.key for requirement in dist.requires()) | |
195 | |
196 # Create a set to remove duplicate packages, and cast it to a list | |
197 # to keep the return type consistent with get_outdated and | |
198 # get_uptodate | |
199 return list({pkg for pkg in packages if pkg.key not in dep_keys}) | |
200 | |
201 def iter_packages_latest_infos(self, packages, options): | |
202 # type: (List[Distribution], Values) -> Iterator[Distribution] | |
203 with self._build_session(options) as session: | |
204 finder = self._build_package_finder(options, session) | |
205 | |
206 def latest_info(dist): | |
207 # type: (Distribution) -> Distribution | |
208 all_candidates = finder.find_all_candidates(dist.key) | |
209 if not options.pre: | |
210 # Remove prereleases | |
211 all_candidates = [candidate for candidate in all_candidates | |
212 if not candidate.version.is_prerelease] | |
213 | |
214 evaluator = finder.make_candidate_evaluator( | |
215 project_name=dist.project_name, | |
216 ) | |
217 best_candidate = evaluator.sort_best_candidate(all_candidates) | |
218 if best_candidate is None: | |
219 return None | |
220 | |
221 remote_version = best_candidate.version | |
222 if best_candidate.link.is_wheel: | |
223 typ = 'wheel' | |
224 else: | |
225 typ = 'sdist' | |
226 # This is dirty but makes the rest of the code much cleaner | |
227 dist.latest_version = remote_version | |
228 dist.latest_filetype = typ | |
229 return dist | |
230 | |
231 for dist in map_multithread(latest_info, packages): | |
232 if dist is not None: | |
233 yield dist | |
234 | |
235 def output_package_listing(self, packages, options): | |
236 # type: (List[Distribution], Values) -> None | |
237 packages = sorted( | |
238 packages, | |
239 key=lambda dist: dist.project_name.lower(), | |
240 ) | |
241 if options.list_format == 'columns' and packages: | |
242 data, header = format_for_columns(packages, options) | |
243 self.output_package_listing_columns(data, header) | |
244 elif options.list_format == 'freeze': | |
245 for dist in packages: | |
246 if options.verbose >= 1: | |
247 write_output("%s==%s (%s)", dist.project_name, | |
248 dist.version, dist.location) | |
249 else: | |
250 write_output("%s==%s", dist.project_name, dist.version) | |
251 elif options.list_format == 'json': | |
252 write_output(format_for_json(packages, options)) | |
253 | |
254 def output_package_listing_columns(self, data, header): | |
255 # type: (List[List[str]], List[str]) -> None | |
256 # insert the header first: we need to know the size of column names | |
257 if len(data) > 0: | |
258 data.insert(0, header) | |
259 | |
260 pkg_strings, sizes = tabulate(data) | |
261 | |
262 # Create and add a separator. | |
263 if len(data) > 0: | |
264 pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) | |
265 | |
266 for val in pkg_strings: | |
267 write_output(val) | |
268 | |
269 | |
270 def format_for_columns(pkgs, options): | |
271 # type: (List[Distribution], Values) -> Tuple[List[List[str]], List[str]] | |
272 """ | |
273 Convert the package data into something usable | |
274 by output_package_listing_columns. | |
275 """ | |
276 running_outdated = options.outdated | |
277 # Adjust the header for the `pip list --outdated` case. | |
278 if running_outdated: | |
279 header = ["Package", "Version", "Latest", "Type"] | |
280 else: | |
281 header = ["Package", "Version"] | |
282 | |
283 data = [] | |
284 if options.verbose >= 1 or any(dist_is_editable(x) for x in pkgs): | |
285 header.append("Location") | |
286 if options.verbose >= 1: | |
287 header.append("Installer") | |
288 | |
289 for proj in pkgs: | |
290 # if we're working on the 'outdated' list, separate out the | |
291 # latest_version and type | |
292 row = [proj.project_name, proj.version] | |
293 | |
294 if running_outdated: | |
295 row.append(proj.latest_version) | |
296 row.append(proj.latest_filetype) | |
297 | |
298 if options.verbose >= 1 or dist_is_editable(proj): | |
299 row.append(proj.location) | |
300 if options.verbose >= 1: | |
301 row.append(get_installer(proj)) | |
302 | |
303 data.append(row) | |
304 | |
305 return data, header | |
306 | |
307 | |
308 def format_for_json(packages, options): | |
309 # type: (List[Distribution], Values) -> str | |
310 data = [] | |
311 for dist in packages: | |
312 info = { | |
313 'name': dist.project_name, | |
314 'version': str(dist.version), | |
315 } | |
316 if options.verbose >= 1: | |
317 info['location'] = dist.location | |
318 info['installer'] = get_installer(dist) | |
319 if options.outdated: | |
320 info['latest_version'] = str(dist.latest_version) | |
321 info['latest_filetype'] = dist.latest_filetype | |
322 data.append(info) | |
323 return json.dumps(data) |