cmdoptions.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. """
  2. shared options and groups
  3. The principle here is to define options once, but *not* instantiate them
  4. globally. One reason being that options with action='append' can carry state
  5. between parses. pip parses general options twice internally, and shouldn't
  6. pass on state. To be consistent, all options will follow this design.
  7. """
  8. # The following comment should be removed at some point in the future.
  9. # mypy: strict-optional=False
  10. import importlib.util
  11. import logging
  12. import os
  13. import textwrap
  14. from functools import partial
  15. from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values
  16. from textwrap import dedent
  17. from typing import Any, Callable, Dict, Optional, Tuple
  18. from pip._vendor.packaging.utils import canonicalize_name
  19. from pip._internal.cli.parser import ConfigOptionParser
  20. from pip._internal.exceptions import CommandError
  21. from pip._internal.locations import USER_CACHE_DIR, get_src_prefix
  22. from pip._internal.models.format_control import FormatControl
  23. from pip._internal.models.index import PyPI
  24. from pip._internal.models.target_python import TargetPython
  25. from pip._internal.utils.hashes import STRONG_HASHES
  26. from pip._internal.utils.misc import strtobool
  27. logger = logging.getLogger(__name__)
  28. def raise_option_error(parser: OptionParser, option: Option, msg: str) -> None:
  29. """
  30. Raise an option parsing error using parser.error().
  31. Args:
  32. parser: an OptionParser instance.
  33. option: an Option instance.
  34. msg: the error text.
  35. """
  36. msg = f"{option} error: {msg}"
  37. msg = textwrap.fill(" ".join(msg.split()))
  38. parser.error(msg)
  39. def make_option_group(group: Dict[str, Any], parser: ConfigOptionParser) -> OptionGroup:
  40. """
  41. Return an OptionGroup object
  42. group -- assumed to be dict with 'name' and 'options' keys
  43. parser -- an optparse Parser
  44. """
  45. option_group = OptionGroup(parser, group["name"])
  46. for option in group["options"]:
  47. option_group.add_option(option())
  48. return option_group
  49. def check_dist_restriction(options: Values, check_target: bool = False) -> None:
  50. """Function for determining if custom platform options are allowed.
  51. :param options: The OptionParser options.
  52. :param check_target: Whether or not to check if --target is being used.
  53. """
  54. dist_restriction_set = any(
  55. [
  56. options.python_version,
  57. options.platforms,
  58. options.abis,
  59. options.implementation,
  60. ]
  61. )
  62. binary_only = FormatControl(set(), {":all:"})
  63. sdist_dependencies_allowed = (
  64. options.format_control != binary_only and not options.ignore_dependencies
  65. )
  66. # Installations or downloads using dist restrictions must not combine
  67. # source distributions and dist-specific wheels, as they are not
  68. # guaranteed to be locally compatible.
  69. if dist_restriction_set and sdist_dependencies_allowed:
  70. raise CommandError(
  71. "When restricting platform and interpreter constraints using "
  72. "--python-version, --platform, --abi, or --implementation, "
  73. "either --no-deps must be set, or --only-binary=:all: must be "
  74. "set and --no-binary must not be set (or must be set to "
  75. ":none:)."
  76. )
  77. if check_target:
  78. if dist_restriction_set and not options.target_dir:
  79. raise CommandError(
  80. "Can not use any platform or abi specific options unless "
  81. "installing via '--target'"
  82. )
  83. def _path_option_check(option: Option, opt: str, value: str) -> str:
  84. return os.path.expanduser(value)
  85. def _package_name_option_check(option: Option, opt: str, value: str) -> str:
  86. return canonicalize_name(value)
  87. class PipOption(Option):
  88. TYPES = Option.TYPES + ("path", "package_name")
  89. TYPE_CHECKER = Option.TYPE_CHECKER.copy()
  90. TYPE_CHECKER["package_name"] = _package_name_option_check
  91. TYPE_CHECKER["path"] = _path_option_check
  92. ###########
  93. # options #
  94. ###########
  95. help_: Callable[..., Option] = partial(
  96. Option,
  97. "-h",
  98. "--help",
  99. dest="help",
  100. action="help",
  101. help="Show help.",
  102. )
  103. debug_mode: Callable[..., Option] = partial(
  104. Option,
  105. "--debug",
  106. dest="debug_mode",
  107. action="store_true",
  108. default=False,
  109. help=(
  110. "Let unhandled exceptions propagate outside the main subroutine, "
  111. "instead of logging them to stderr."
  112. ),
  113. )
  114. isolated_mode: Callable[..., Option] = partial(
  115. Option,
  116. "--isolated",
  117. dest="isolated_mode",
  118. action="store_true",
  119. default=False,
  120. help=(
  121. "Run pip in an isolated mode, ignoring environment variables and user "
  122. "configuration."
  123. ),
  124. )
  125. require_virtualenv: Callable[..., Option] = partial(
  126. Option,
  127. "--require-virtualenv",
  128. "--require-venv",
  129. dest="require_venv",
  130. action="store_true",
  131. default=False,
  132. help=(
  133. "Allow pip to only run in a virtual environment; "
  134. "exit with an error otherwise."
  135. ),
  136. )
  137. override_externally_managed: Callable[..., Option] = partial(
  138. Option,
  139. "--break-system-packages",
  140. dest="override_externally_managed",
  141. action="store_true",
  142. help="Allow pip to modify an EXTERNALLY-MANAGED Python installation",
  143. )
  144. python: Callable[..., Option] = partial(
  145. Option,
  146. "--python",
  147. dest="python",
  148. help="Run pip with the specified Python interpreter.",
  149. )
  150. verbose: Callable[..., Option] = partial(
  151. Option,
  152. "-v",
  153. "--verbose",
  154. dest="verbose",
  155. action="count",
  156. default=0,
  157. help="Give more output. Option is additive, and can be used up to 3 times.",
  158. )
  159. no_color: Callable[..., Option] = partial(
  160. Option,
  161. "--no-color",
  162. dest="no_color",
  163. action="store_true",
  164. default=False,
  165. help="Suppress colored output.",
  166. )
  167. version: Callable[..., Option] = partial(
  168. Option,
  169. "-V",
  170. "--version",
  171. dest="version",
  172. action="store_true",
  173. help="Show version and exit.",
  174. )
  175. quiet: Callable[..., Option] = partial(
  176. Option,
  177. "-q",
  178. "--quiet",
  179. dest="quiet",
  180. action="count",
  181. default=0,
  182. help=(
  183. "Give less output. Option is additive, and can be used up to 3"
  184. " times (corresponding to WARNING, ERROR, and CRITICAL logging"
  185. " levels)."
  186. ),
  187. )
  188. progress_bar: Callable[..., Option] = partial(
  189. Option,
  190. "--progress-bar",
  191. dest="progress_bar",
  192. type="choice",
  193. choices=["on", "off"],
  194. default="on",
  195. help="Specify whether the progress bar should be used [on, off] (default: on)",
  196. )
  197. log: Callable[..., Option] = partial(
  198. PipOption,
  199. "--log",
  200. "--log-file",
  201. "--local-log",
  202. dest="log",
  203. metavar="path",
  204. type="path",
  205. help="Path to a verbose appending log.",
  206. )
  207. no_input: Callable[..., Option] = partial(
  208. Option,
  209. # Don't ask for input
  210. "--no-input",
  211. dest="no_input",
  212. action="store_true",
  213. default=False,
  214. help="Disable prompting for input.",
  215. )
  216. keyring_provider: Callable[..., Option] = partial(
  217. Option,
  218. "--keyring-provider",
  219. dest="keyring_provider",
  220. choices=["auto", "disabled", "import", "subprocess"],
  221. default="auto",
  222. help=(
  223. "Enable the credential lookup via the keyring library if user input is allowed."
  224. " Specify which mechanism to use [disabled, import, subprocess]."
  225. " (default: disabled)"
  226. ),
  227. )
  228. proxy: Callable[..., Option] = partial(
  229. Option,
  230. "--proxy",
  231. dest="proxy",
  232. type="str",
  233. default="",
  234. help="Specify a proxy in the form scheme://[user:passwd@]proxy.server:port.",
  235. )
  236. retries: Callable[..., Option] = partial(
  237. Option,
  238. "--retries",
  239. dest="retries",
  240. type="int",
  241. default=5,
  242. help="Maximum number of retries each connection should attempt "
  243. "(default %default times).",
  244. )
  245. timeout: Callable[..., Option] = partial(
  246. Option,
  247. "--timeout",
  248. "--default-timeout",
  249. metavar="sec",
  250. dest="timeout",
  251. type="float",
  252. default=15,
  253. help="Set the socket timeout (default %default seconds).",
  254. )
  255. def exists_action() -> Option:
  256. return Option(
  257. # Option when path already exist
  258. "--exists-action",
  259. dest="exists_action",
  260. type="choice",
  261. choices=["s", "i", "w", "b", "a"],
  262. default=[],
  263. action="append",
  264. metavar="action",
  265. help="Default action when a path already exists: "
  266. "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.",
  267. )
  268. cert: Callable[..., Option] = partial(
  269. PipOption,
  270. "--cert",
  271. dest="cert",
  272. type="path",
  273. metavar="path",
  274. help=(
  275. "Path to PEM-encoded CA certificate bundle. "
  276. "If provided, overrides the default. "
  277. "See 'SSL Certificate Verification' in pip documentation "
  278. "for more information."
  279. ),
  280. )
  281. client_cert: Callable[..., Option] = partial(
  282. PipOption,
  283. "--client-cert",
  284. dest="client_cert",
  285. type="path",
  286. default=None,
  287. metavar="path",
  288. help="Path to SSL client certificate, a single file containing the "
  289. "private key and the certificate in PEM format.",
  290. )
  291. index_url: Callable[..., Option] = partial(
  292. Option,
  293. "-i",
  294. "--index-url",
  295. "--pypi-url",
  296. dest="index_url",
  297. metavar="URL",
  298. default=PyPI.simple_url,
  299. help="Base URL of the Python Package Index (default %default). "
  300. "This should point to a repository compliant with PEP 503 "
  301. "(the simple repository API) or a local directory laid out "
  302. "in the same format.",
  303. )
  304. def extra_index_url() -> Option:
  305. return Option(
  306. "--extra-index-url",
  307. dest="extra_index_urls",
  308. metavar="URL",
  309. action="append",
  310. default=[],
  311. help="Extra URLs of package indexes to use in addition to "
  312. "--index-url. Should follow the same rules as "
  313. "--index-url.",
  314. )
  315. no_index: Callable[..., Option] = partial(
  316. Option,
  317. "--no-index",
  318. dest="no_index",
  319. action="store_true",
  320. default=False,
  321. help="Ignore package index (only looking at --find-links URLs instead).",
  322. )
  323. def find_links() -> Option:
  324. return Option(
  325. "-f",
  326. "--find-links",
  327. dest="find_links",
  328. action="append",
  329. default=[],
  330. metavar="url",
  331. help="If a URL or path to an html file, then parse for links to "
  332. "archives such as sdist (.tar.gz) or wheel (.whl) files. "
  333. "If a local path or file:// URL that's a directory, "
  334. "then look for archives in the directory listing. "
  335. "Links to VCS project URLs are not supported.",
  336. )
  337. def trusted_host() -> Option:
  338. return Option(
  339. "--trusted-host",
  340. dest="trusted_hosts",
  341. action="append",
  342. metavar="HOSTNAME",
  343. default=[],
  344. help="Mark this host or host:port pair as trusted, even though it "
  345. "does not have valid or any HTTPS.",
  346. )
  347. def constraints() -> Option:
  348. return Option(
  349. "-c",
  350. "--constraint",
  351. dest="constraints",
  352. action="append",
  353. default=[],
  354. metavar="file",
  355. help="Constrain versions using the given constraints file. "
  356. "This option can be used multiple times.",
  357. )
  358. def requirements() -> Option:
  359. return Option(
  360. "-r",
  361. "--requirement",
  362. dest="requirements",
  363. action="append",
  364. default=[],
  365. metavar="file",
  366. help="Install from the given requirements file. "
  367. "This option can be used multiple times.",
  368. )
  369. def editable() -> Option:
  370. return Option(
  371. "-e",
  372. "--editable",
  373. dest="editables",
  374. action="append",
  375. default=[],
  376. metavar="path/url",
  377. help=(
  378. "Install a project in editable mode (i.e. setuptools "
  379. '"develop mode") from a local project path or a VCS url.'
  380. ),
  381. )
  382. def _handle_src(option: Option, opt_str: str, value: str, parser: OptionParser) -> None:
  383. value = os.path.abspath(value)
  384. setattr(parser.values, option.dest, value)
  385. src: Callable[..., Option] = partial(
  386. PipOption,
  387. "--src",
  388. "--source",
  389. "--source-dir",
  390. "--source-directory",
  391. dest="src_dir",
  392. type="path",
  393. metavar="dir",
  394. default=get_src_prefix(),
  395. action="callback",
  396. callback=_handle_src,
  397. help="Directory to check out editable projects into. "
  398. 'The default in a virtualenv is "<venv path>/src". '
  399. 'The default for global installs is "<current dir>/src".',
  400. )
  401. def _get_format_control(values: Values, option: Option) -> Any:
  402. """Get a format_control object."""
  403. return getattr(values, option.dest)
  404. def _handle_no_binary(
  405. option: Option, opt_str: str, value: str, parser: OptionParser
  406. ) -> None:
  407. existing = _get_format_control(parser.values, option)
  408. FormatControl.handle_mutual_excludes(
  409. value,
  410. existing.no_binary,
  411. existing.only_binary,
  412. )
  413. def _handle_only_binary(
  414. option: Option, opt_str: str, value: str, parser: OptionParser
  415. ) -> None:
  416. existing = _get_format_control(parser.values, option)
  417. FormatControl.handle_mutual_excludes(
  418. value,
  419. existing.only_binary,
  420. existing.no_binary,
  421. )
  422. def no_binary() -> Option:
  423. format_control = FormatControl(set(), set())
  424. return Option(
  425. "--no-binary",
  426. dest="format_control",
  427. action="callback",
  428. callback=_handle_no_binary,
  429. type="str",
  430. default=format_control,
  431. help="Do not use binary packages. Can be supplied multiple times, and "
  432. 'each time adds to the existing value. Accepts either ":all:" to '
  433. 'disable all binary packages, ":none:" to empty the set (notice '
  434. "the colons), or one or more package names with commas between "
  435. "them (no colons). Note that some packages are tricky to compile "
  436. "and may fail to install when this option is used on them.",
  437. )
  438. def only_binary() -> Option:
  439. format_control = FormatControl(set(), set())
  440. return Option(
  441. "--only-binary",
  442. dest="format_control",
  443. action="callback",
  444. callback=_handle_only_binary,
  445. type="str",
  446. default=format_control,
  447. help="Do not use source packages. Can be supplied multiple times, and "
  448. 'each time adds to the existing value. Accepts either ":all:" to '
  449. 'disable all source packages, ":none:" to empty the set, or one '
  450. "or more package names with commas between them. Packages "
  451. "without binary distributions will fail to install when this "
  452. "option is used on them.",
  453. )
  454. platforms: Callable[..., Option] = partial(
  455. Option,
  456. "--platform",
  457. dest="platforms",
  458. metavar="platform",
  459. action="append",
  460. default=None,
  461. help=(
  462. "Only use wheels compatible with <platform>. Defaults to the "
  463. "platform of the running system. Use this option multiple times to "
  464. "specify multiple platforms supported by the target interpreter."
  465. ),
  466. )
  467. # This was made a separate function for unit-testing purposes.
  468. def _convert_python_version(value: str) -> Tuple[Tuple[int, ...], Optional[str]]:
  469. """
  470. Convert a version string like "3", "37", or "3.7.3" into a tuple of ints.
  471. :return: A 2-tuple (version_info, error_msg), where `error_msg` is
  472. non-None if and only if there was a parsing error.
  473. """
  474. if not value:
  475. # The empty string is the same as not providing a value.
  476. return (None, None)
  477. parts = value.split(".")
  478. if len(parts) > 3:
  479. return ((), "at most three version parts are allowed")
  480. if len(parts) == 1:
  481. # Then we are in the case of "3" or "37".
  482. value = parts[0]
  483. if len(value) > 1:
  484. parts = [value[0], value[1:]]
  485. try:
  486. version_info = tuple(int(part) for part in parts)
  487. except ValueError:
  488. return ((), "each version part must be an integer")
  489. return (version_info, None)
  490. def _handle_python_version(
  491. option: Option, opt_str: str, value: str, parser: OptionParser
  492. ) -> None:
  493. """
  494. Handle a provided --python-version value.
  495. """
  496. version_info, error_msg = _convert_python_version(value)
  497. if error_msg is not None:
  498. msg = "invalid --python-version value: {!r}: {}".format(
  499. value,
  500. error_msg,
  501. )
  502. raise_option_error(parser, option=option, msg=msg)
  503. parser.values.python_version = version_info
  504. python_version: Callable[..., Option] = partial(
  505. Option,
  506. "--python-version",
  507. dest="python_version",
  508. metavar="python_version",
  509. action="callback",
  510. callback=_handle_python_version,
  511. type="str",
  512. default=None,
  513. help=dedent(
  514. """\
  515. The Python interpreter version to use for wheel and "Requires-Python"
  516. compatibility checks. Defaults to a version derived from the running
  517. interpreter. The version can be specified using up to three dot-separated
  518. integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor
  519. version can also be given as a string without dots (e.g. "37" for 3.7.0).
  520. """
  521. ),
  522. )
  523. implementation: Callable[..., Option] = partial(
  524. Option,
  525. "--implementation",
  526. dest="implementation",
  527. metavar="implementation",
  528. default=None,
  529. help=(
  530. "Only use wheels compatible with Python "
  531. "implementation <implementation>, e.g. 'pp', 'jy', 'cp', "
  532. " or 'ip'. If not specified, then the current "
  533. "interpreter implementation is used. Use 'py' to force "
  534. "implementation-agnostic wheels."
  535. ),
  536. )
  537. abis: Callable[..., Option] = partial(
  538. Option,
  539. "--abi",
  540. dest="abis",
  541. metavar="abi",
  542. action="append",
  543. default=None,
  544. help=(
  545. "Only use wheels compatible with Python abi <abi>, e.g. 'pypy_41'. "
  546. "If not specified, then the current interpreter abi tag is used. "
  547. "Use this option multiple times to specify multiple abis supported "
  548. "by the target interpreter. Generally you will need to specify "
  549. "--implementation, --platform, and --python-version when using this "
  550. "option."
  551. ),
  552. )
  553. def add_target_python_options(cmd_opts: OptionGroup) -> None:
  554. cmd_opts.add_option(platforms())
  555. cmd_opts.add_option(python_version())
  556. cmd_opts.add_option(implementation())
  557. cmd_opts.add_option(abis())
  558. def make_target_python(options: Values) -> TargetPython:
  559. target_python = TargetPython(
  560. platforms=options.platforms,
  561. py_version_info=options.python_version,
  562. abis=options.abis,
  563. implementation=options.implementation,
  564. )
  565. return target_python
  566. def prefer_binary() -> Option:
  567. return Option(
  568. "--prefer-binary",
  569. dest="prefer_binary",
  570. action="store_true",
  571. default=False,
  572. help="Prefer older binary packages over newer source packages.",
  573. )
  574. cache_dir: Callable[..., Option] = partial(
  575. PipOption,
  576. "--cache-dir",
  577. dest="cache_dir",
  578. default=USER_CACHE_DIR,
  579. metavar="dir",
  580. type="path",
  581. help="Store the cache data in <dir>.",
  582. )
  583. def _handle_no_cache_dir(
  584. option: Option, opt: str, value: str, parser: OptionParser
  585. ) -> None:
  586. """
  587. Process a value provided for the --no-cache-dir option.
  588. This is an optparse.Option callback for the --no-cache-dir option.
  589. """
  590. # The value argument will be None if --no-cache-dir is passed via the
  591. # command-line, since the option doesn't accept arguments. However,
  592. # the value can be non-None if the option is triggered e.g. by an
  593. # environment variable, like PIP_NO_CACHE_DIR=true.
  594. if value is not None:
  595. # Then parse the string value to get argument error-checking.
  596. try:
  597. strtobool(value)
  598. except ValueError as exc:
  599. raise_option_error(parser, option=option, msg=str(exc))
  600. # Originally, setting PIP_NO_CACHE_DIR to a value that strtobool()
  601. # converted to 0 (like "false" or "no") caused cache_dir to be disabled
  602. # rather than enabled (logic would say the latter). Thus, we disable
  603. # the cache directory not just on values that parse to True, but (for
  604. # backwards compatibility reasons) also on values that parse to False.
  605. # In other words, always set it to False if the option is provided in
  606. # some (valid) form.
  607. parser.values.cache_dir = False
  608. no_cache: Callable[..., Option] = partial(
  609. Option,
  610. "--no-cache-dir",
  611. dest="cache_dir",
  612. action="callback",
  613. callback=_handle_no_cache_dir,
  614. help="Disable the cache.",
  615. )
  616. no_deps: Callable[..., Option] = partial(
  617. Option,
  618. "--no-deps",
  619. "--no-dependencies",
  620. dest="ignore_dependencies",
  621. action="store_true",
  622. default=False,
  623. help="Don't install package dependencies.",
  624. )
  625. ignore_requires_python: Callable[..., Option] = partial(
  626. Option,
  627. "--ignore-requires-python",
  628. dest="ignore_requires_python",
  629. action="store_true",
  630. help="Ignore the Requires-Python information.",
  631. )
  632. no_build_isolation: Callable[..., Option] = partial(
  633. Option,
  634. "--no-build-isolation",
  635. dest="build_isolation",
  636. action="store_false",
  637. default=True,
  638. help="Disable isolation when building a modern source distribution. "
  639. "Build dependencies specified by PEP 518 must be already installed "
  640. "if this option is used.",
  641. )
  642. check_build_deps: Callable[..., Option] = partial(
  643. Option,
  644. "--check-build-dependencies",
  645. dest="check_build_deps",
  646. action="store_true",
  647. default=False,
  648. help="Check the build dependencies when PEP517 is used.",
  649. )
  650. def _handle_no_use_pep517(
  651. option: Option, opt: str, value: str, parser: OptionParser
  652. ) -> None:
  653. """
  654. Process a value provided for the --no-use-pep517 option.
  655. This is an optparse.Option callback for the no_use_pep517 option.
  656. """
  657. # Since --no-use-pep517 doesn't accept arguments, the value argument
  658. # will be None if --no-use-pep517 is passed via the command-line.
  659. # However, the value can be non-None if the option is triggered e.g.
  660. # by an environment variable, for example "PIP_NO_USE_PEP517=true".
  661. if value is not None:
  662. msg = """A value was passed for --no-use-pep517,
  663. probably using either the PIP_NO_USE_PEP517 environment variable
  664. or the "no-use-pep517" config file option. Use an appropriate value
  665. of the PIP_USE_PEP517 environment variable or the "use-pep517"
  666. config file option instead.
  667. """
  668. raise_option_error(parser, option=option, msg=msg)
  669. # If user doesn't wish to use pep517, we check if setuptools and wheel are installed
  670. # and raise error if it is not.
  671. packages = ("setuptools", "wheel")
  672. if not all(importlib.util.find_spec(package) for package in packages):
  673. msg = (
  674. f"It is not possible to use --no-use-pep517 "
  675. f"without {' and '.join(packages)} installed."
  676. )
  677. raise_option_error(parser, option=option, msg=msg)
  678. # Otherwise, --no-use-pep517 was passed via the command-line.
  679. parser.values.use_pep517 = False
  680. use_pep517: Any = partial(
  681. Option,
  682. "--use-pep517",
  683. dest="use_pep517",
  684. action="store_true",
  685. default=None,
  686. help="Use PEP 517 for building source distributions "
  687. "(use --no-use-pep517 to force legacy behaviour).",
  688. )
  689. no_use_pep517: Any = partial(
  690. Option,
  691. "--no-use-pep517",
  692. dest="use_pep517",
  693. action="callback",
  694. callback=_handle_no_use_pep517,
  695. default=None,
  696. help=SUPPRESS_HELP,
  697. )
  698. def _handle_config_settings(
  699. option: Option, opt_str: str, value: str, parser: OptionParser
  700. ) -> None:
  701. key, sep, val = value.partition("=")
  702. if sep != "=":
  703. parser.error(f"Arguments to {opt_str} must be of the form KEY=VAL") # noqa
  704. dest = getattr(parser.values, option.dest)
  705. if dest is None:
  706. dest = {}
  707. setattr(parser.values, option.dest, dest)
  708. if key in dest:
  709. if isinstance(dest[key], list):
  710. dest[key].append(val)
  711. else:
  712. dest[key] = [dest[key], val]
  713. else:
  714. dest[key] = val
  715. config_settings: Callable[..., Option] = partial(
  716. Option,
  717. "-C",
  718. "--config-settings",
  719. dest="config_settings",
  720. type=str,
  721. action="callback",
  722. callback=_handle_config_settings,
  723. metavar="settings",
  724. help="Configuration settings to be passed to the PEP 517 build backend. "
  725. "Settings take the form KEY=VALUE. Use multiple --config-settings options "
  726. "to pass multiple keys to the backend.",
  727. )
  728. build_options: Callable[..., Option] = partial(
  729. Option,
  730. "--build-option",
  731. dest="build_options",
  732. metavar="options",
  733. action="append",
  734. help="Extra arguments to be supplied to 'setup.py bdist_wheel'.",
  735. )
  736. global_options: Callable[..., Option] = partial(
  737. Option,
  738. "--global-option",
  739. dest="global_options",
  740. action="append",
  741. metavar="options",
  742. help="Extra global options to be supplied to the setup.py "
  743. "call before the install or bdist_wheel command.",
  744. )
  745. no_clean: Callable[..., Option] = partial(
  746. Option,
  747. "--no-clean",
  748. action="store_true",
  749. default=False,
  750. help="Don't clean up build directories.",
  751. )
  752. pre: Callable[..., Option] = partial(
  753. Option,
  754. "--pre",
  755. action="store_true",
  756. default=False,
  757. help="Include pre-release and development versions. By default, "
  758. "pip only finds stable versions.",
  759. )
  760. disable_pip_version_check: Callable[..., Option] = partial(
  761. Option,
  762. "--disable-pip-version-check",
  763. dest="disable_pip_version_check",
  764. action="store_true",
  765. default=False,
  766. help="Don't periodically check PyPI to determine whether a new version "
  767. "of pip is available for download. Implied with --no-index.",
  768. )
  769. root_user_action: Callable[..., Option] = partial(
  770. Option,
  771. "--root-user-action",
  772. dest="root_user_action",
  773. default="warn",
  774. choices=["warn", "ignore"],
  775. help="Action if pip is run as a root user. By default, a warning message is shown.",
  776. )
  777. def _handle_merge_hash(
  778. option: Option, opt_str: str, value: str, parser: OptionParser
  779. ) -> None:
  780. """Given a value spelled "algo:digest", append the digest to a list
  781. pointed to in a dict by the algo name."""
  782. if not parser.values.hashes:
  783. parser.values.hashes = {}
  784. try:
  785. algo, digest = value.split(":", 1)
  786. except ValueError:
  787. parser.error(
  788. "Arguments to {} must be a hash name " # noqa
  789. "followed by a value, like --hash=sha256:"
  790. "abcde...".format(opt_str)
  791. )
  792. if algo not in STRONG_HASHES:
  793. parser.error(
  794. "Allowed hash algorithms for {} are {}.".format( # noqa
  795. opt_str, ", ".join(STRONG_HASHES)
  796. )
  797. )
  798. parser.values.hashes.setdefault(algo, []).append(digest)
  799. hash: Callable[..., Option] = partial(
  800. Option,
  801. "--hash",
  802. # Hash values eventually end up in InstallRequirement.hashes due to
  803. # __dict__ copying in process_line().
  804. dest="hashes",
  805. action="callback",
  806. callback=_handle_merge_hash,
  807. type="string",
  808. help="Verify that the package's archive matches this "
  809. "hash before installing. Example: --hash=sha256:abcdef...",
  810. )
  811. require_hashes: Callable[..., Option] = partial(
  812. Option,
  813. "--require-hashes",
  814. dest="require_hashes",
  815. action="store_true",
  816. default=False,
  817. help="Require a hash to check each requirement against, for "
  818. "repeatable installs. This option is implied when any package in a "
  819. "requirements file has a --hash option.",
  820. )
  821. list_path: Callable[..., Option] = partial(
  822. PipOption,
  823. "--path",
  824. dest="path",
  825. type="path",
  826. action="append",
  827. help="Restrict to the specified installation path for listing "
  828. "packages (can be used multiple times).",
  829. )
  830. def check_list_path_option(options: Values) -> None:
  831. if options.path and (options.user or options.local):
  832. raise CommandError("Cannot combine '--path' with '--user' or '--local'")
  833. list_exclude: Callable[..., Option] = partial(
  834. PipOption,
  835. "--exclude",
  836. dest="excludes",
  837. action="append",
  838. metavar="package",
  839. type="package_name",
  840. help="Exclude specified package from the output",
  841. )
  842. no_python_version_warning: Callable[..., Option] = partial(
  843. Option,
  844. "--no-python-version-warning",
  845. dest="no_python_version_warning",
  846. action="store_true",
  847. default=False,
  848. help="Silence deprecation warnings for upcoming unsupported Pythons.",
  849. )
  850. # Features that are now always on. A warning is printed if they are used.
  851. ALWAYS_ENABLED_FEATURES = [
  852. "no-binary-enable-wheel-cache", # always on since 23.1
  853. ]
  854. use_new_feature: Callable[..., Option] = partial(
  855. Option,
  856. "--use-feature",
  857. dest="features_enabled",
  858. metavar="feature",
  859. action="append",
  860. default=[],
  861. choices=[
  862. "fast-deps",
  863. "truststore",
  864. ]
  865. + ALWAYS_ENABLED_FEATURES,
  866. help="Enable new functionality, that may be backward incompatible.",
  867. )
  868. use_deprecated_feature: Callable[..., Option] = partial(
  869. Option,
  870. "--use-deprecated",
  871. dest="deprecated_features_enabled",
  872. metavar="feature",
  873. action="append",
  874. default=[],
  875. choices=[
  876. "legacy-resolver",
  877. ],
  878. help=("Enable deprecated functionality, that will be removed in the future."),
  879. )
  880. ##########
  881. # groups #
  882. ##########
  883. general_group: Dict[str, Any] = {
  884. "name": "General Options",
  885. "options": [
  886. help_,
  887. debug_mode,
  888. isolated_mode,
  889. require_virtualenv,
  890. python,
  891. verbose,
  892. version,
  893. quiet,
  894. log,
  895. no_input,
  896. keyring_provider,
  897. proxy,
  898. retries,
  899. timeout,
  900. exists_action,
  901. trusted_host,
  902. cert,
  903. client_cert,
  904. cache_dir,
  905. no_cache,
  906. disable_pip_version_check,
  907. no_color,
  908. no_python_version_warning,
  909. use_new_feature,
  910. use_deprecated_feature,
  911. ],
  912. }
  913. index_group: Dict[str, Any] = {
  914. "name": "Package Index Options",
  915. "options": [
  916. index_url,
  917. extra_index_url,
  918. no_index,
  919. find_links,
  920. ],
  921. }