2 from optparse
import Values
3 from typing
import Any
, Iterable
, List
, Optional
, Union
5 from pip
._vendor
.packaging
.version
import LegacyVersion
, Version
7 from pip
._internal
.cli
import cmdoptions
8 from pip
._internal
.cli
.req_command
import IndexGroupCommand
9 from pip
._internal
.cli
.status_codes
import ERROR
, SUCCESS
10 from pip
._internal
.commands
.search
import print_dist_installation_info
11 from pip
._internal
.exceptions
import CommandError
, DistributionNotFound
, PipError
12 from pip
._internal
.index
.collector
import LinkCollector
13 from pip
._internal
.index
.package_finder
import PackageFinder
14 from pip
._internal
.models
.selection_prefs
import SelectionPreferences
15 from pip
._internal
.models
.target_python
import TargetPython
16 from pip
._internal
.network
.session
import PipSession
17 from pip
._internal
.utils
.misc
import write_output
19 logger
= logging
.getLogger(__name__
)
22 class IndexCommand(IndexGroupCommand
):
24 Inspect information available from package indexes.
27 ignore_require_venv
= True
29 %prog versions <package>
32 def add_options(self
) -> None:
33 cmdoptions
.add_target_python_options(self
.cmd_opts
)
35 self
.cmd_opts
.add_option(cmdoptions
.ignore_requires_python())
36 self
.cmd_opts
.add_option(cmdoptions
.pre())
37 self
.cmd_opts
.add_option(cmdoptions
.no_binary())
38 self
.cmd_opts
.add_option(cmdoptions
.only_binary())
40 index_opts
= cmdoptions
.make_option_group(
41 cmdoptions
.index_group
,
45 self
.parser
.insert_option_group(0, index_opts
)
46 self
.parser
.insert_option_group(0, self
.cmd_opts
)
48 def run(self
, options
: Values
, args
: List
[str]) -> int:
50 "versions": self
.get_available_package_versions
,
54 "pip index is currently an experimental command. "
55 "It may be removed/changed in a future release "
56 "without prior warning."
60 if not args
or args
[0] not in handlers
:
62 "Need an action (%s) to perform.",
63 ", ".join(sorted(handlers
)),
69 # Error handling happens here, not in the action-handlers.
71 handlers
[action
](options
, args
[1:])
73 logger
.error(e
.args
[0])
78 def _build_package_finder(
82 target_python
: Optional
[TargetPython
] = None,
83 ignore_requires_python
: Optional
[bool] = None,
86 Create a package finder appropriate to the index command.
88 link_collector
= LinkCollector
.create(session
, options
=options
)
90 # Pass allow_yanked=False to ignore yanked versions.
91 selection_prefs
= SelectionPreferences(
93 allow_all_prereleases
=options
.pre
,
94 ignore_requires_python
=ignore_requires_python
,
97 return PackageFinder
.create(
98 link_collector
=link_collector
,
99 selection_prefs
=selection_prefs
,
100 target_python
=target_python
,
103 def get_available_package_versions(self
, options
: Values
, args
: List
[Any
]) -> None:
105 raise CommandError("You need to specify exactly one argument")
107 target_python
= cmdoptions
.make_target_python(options
)
110 with self
._build
_session
(options
) as session
:
111 finder
= self
._build
_package
_finder
(
114 target_python
=target_python
,
115 ignore_requires_python
=options
.ignore_requires_python
,
118 versions
: Iterable
[Union
[LegacyVersion
, Version
]] = (
119 candidate
.version
for candidate
in finder
.find_all_candidates(query
)
125 version
for version
in versions
if not version
.is_prerelease
127 versions
= set(versions
)
130 raise DistributionNotFound(
131 "No matching distribution found for {}".format(query
)
134 formatted_versions
= [str(ver
) for ver
in sorted(versions
, reverse
=True)]
135 latest
= formatted_versions
[0]
137 write_output("{} ({})".format(query
, latest
))
138 write_output("Available versions: {}".format(", ".join(formatted_versions
)))
139 print_dist_installation_info(query
, latest
)