cmdoptions.py 29 KB

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