Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py: 69%

200 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:48 +0000

1""" 

2shared options and groups 

3 

4The principle here is to define options once, but *not* instantiate them 

5globally. One reason being that options with action='append' can carry state 

6between parses. pip parses general options twice internally, and shouldn't 

7pass on state. To be consistent, all options will follow this design. 

8""" 

9 

10# The following comment should be removed at some point in the future. 

11# mypy: strict-optional=False 

12 

13import importlib.util 

14import logging 

15import os 

16import textwrap 

17from functools import partial 

18from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values 

19from textwrap import dedent 

20from typing import Any, Callable, Dict, Optional, Tuple 

21 

22from pip._vendor.packaging.utils import canonicalize_name 

23 

24from pip._internal.cli.parser import ConfigOptionParser 

25from pip._internal.exceptions import CommandError 

26from pip._internal.locations import USER_CACHE_DIR, get_src_prefix 

27from pip._internal.models.format_control import FormatControl 

28from pip._internal.models.index import PyPI 

29from pip._internal.models.target_python import TargetPython 

30from pip._internal.utils.hashes import STRONG_HASHES 

31from pip._internal.utils.misc import strtobool 

32 

33logger = logging.getLogger(__name__) 

34 

35 

36def raise_option_error(parser: OptionParser, option: Option, msg: str) -> None: 

37 """ 

38 Raise an option parsing error using parser.error(). 

39 

40 Args: 

41 parser: an OptionParser instance. 

42 option: an Option instance. 

43 msg: the error text. 

44 """ 

45 msg = f"{option} error: {msg}" 

46 msg = textwrap.fill(" ".join(msg.split())) 

47 parser.error(msg) 

48 

49 

50def make_option_group(group: Dict[str, Any], parser: ConfigOptionParser) -> OptionGroup: 

51 """ 

52 Return an OptionGroup object 

53 group -- assumed to be dict with 'name' and 'options' keys 

54 parser -- an optparse Parser 

55 """ 

56 option_group = OptionGroup(parser, group["name"]) 

57 for option in group["options"]: 

58 option_group.add_option(option()) 

59 return option_group 

60 

61 

62def check_dist_restriction(options: Values, check_target: bool = False) -> None: 

63 """Function for determining if custom platform options are allowed. 

64 

65 :param options: The OptionParser options. 

66 :param check_target: Whether or not to check if --target is being used. 

67 """ 

68 dist_restriction_set = any( 

69 [ 

70 options.python_version, 

71 options.platforms, 

72 options.abis, 

73 options.implementation, 

74 ] 

75 ) 

76 

77 binary_only = FormatControl(set(), {":all:"}) 

78 sdist_dependencies_allowed = ( 

79 options.format_control != binary_only and not options.ignore_dependencies 

80 ) 

81 

82 # Installations or downloads using dist restrictions must not combine 

83 # source distributions and dist-specific wheels, as they are not 

84 # guaranteed to be locally compatible. 

85 if dist_restriction_set and sdist_dependencies_allowed: 

86 raise CommandError( 

87 "When restricting platform and interpreter constraints using " 

88 "--python-version, --platform, --abi, or --implementation, " 

89 "either --no-deps must be set, or --only-binary=:all: must be " 

90 "set and --no-binary must not be set (or must be set to " 

91 ":none:)." 

92 ) 

93 

94 if check_target: 

95 if dist_restriction_set and not options.target_dir: 

96 raise CommandError( 

97 "Can not use any platform or abi specific options unless " 

98 "installing via '--target'" 

99 ) 

100 

101 

102def _path_option_check(option: Option, opt: str, value: str) -> str: 

103 return os.path.expanduser(value) 

104 

105 

106def _package_name_option_check(option: Option, opt: str, value: str) -> str: 

107 return canonicalize_name(value) 

108 

109 

110class PipOption(Option): 

111 TYPES = Option.TYPES + ("path", "package_name") 

112 TYPE_CHECKER = Option.TYPE_CHECKER.copy() 

113 TYPE_CHECKER["package_name"] = _package_name_option_check 

114 TYPE_CHECKER["path"] = _path_option_check 

115 

116 

117########### 

118# options # 

119########### 

120 

121help_: Callable[..., Option] = partial( 

122 Option, 

123 "-h", 

124 "--help", 

125 dest="help", 

126 action="help", 

127 help="Show help.", 

128) 

129 

130debug_mode: Callable[..., Option] = partial( 

131 Option, 

132 "--debug", 

133 dest="debug_mode", 

134 action="store_true", 

135 default=False, 

136 help=( 

137 "Let unhandled exceptions propagate outside the main subroutine, " 

138 "instead of logging them to stderr." 

139 ), 

140) 

141 

142isolated_mode: Callable[..., Option] = partial( 

143 Option, 

144 "--isolated", 

145 dest="isolated_mode", 

146 action="store_true", 

147 default=False, 

148 help=( 

149 "Run pip in an isolated mode, ignoring environment variables and user " 

150 "configuration." 

151 ), 

152) 

153 

154require_virtualenv: Callable[..., Option] = partial( 

155 Option, 

156 "--require-virtualenv", 

157 "--require-venv", 

158 dest="require_venv", 

159 action="store_true", 

160 default=False, 

161 help=( 

162 "Allow pip to only run in a virtual environment; " 

163 "exit with an error otherwise." 

164 ), 

165) 

166 

167override_externally_managed: Callable[..., Option] = partial( 

168 Option, 

169 "--break-system-packages", 

170 dest="override_externally_managed", 

171 action="store_true", 

172 help="Allow pip to modify an EXTERNALLY-MANAGED Python installation", 

173) 

174 

175python: Callable[..., Option] = partial( 

176 Option, 

177 "--python", 

178 dest="python", 

179 help="Run pip with the specified Python interpreter.", 

180) 

181 

182verbose: Callable[..., Option] = partial( 

183 Option, 

184 "-v", 

185 "--verbose", 

186 dest="verbose", 

187 action="count", 

188 default=0, 

189 help="Give more output. Option is additive, and can be used up to 3 times.", 

190) 

191 

192no_color: Callable[..., Option] = partial( 

193 Option, 

194 "--no-color", 

195 dest="no_color", 

196 action="store_true", 

197 default=False, 

198 help="Suppress colored output.", 

199) 

200 

201version: Callable[..., Option] = partial( 

202 Option, 

203 "-V", 

204 "--version", 

205 dest="version", 

206 action="store_true", 

207 help="Show version and exit.", 

208) 

209 

210quiet: Callable[..., Option] = partial( 

211 Option, 

212 "-q", 

213 "--quiet", 

214 dest="quiet", 

215 action="count", 

216 default=0, 

217 help=( 

218 "Give less output. Option is additive, and can be used up to 3" 

219 " times (corresponding to WARNING, ERROR, and CRITICAL logging" 

220 " levels)." 

221 ), 

222) 

223 

224progress_bar: Callable[..., Option] = partial( 

225 Option, 

226 "--progress-bar", 

227 dest="progress_bar", 

228 type="choice", 

229 choices=["on", "off"], 

230 default="on", 

231 help="Specify whether the progress bar should be used [on, off] (default: on)", 

232) 

233 

234log: Callable[..., Option] = partial( 

235 PipOption, 

236 "--log", 

237 "--log-file", 

238 "--local-log", 

239 dest="log", 

240 metavar="path", 

241 type="path", 

242 help="Path to a verbose appending log.", 

243) 

244 

245no_input: Callable[..., Option] = partial( 

246 Option, 

247 # Don't ask for input 

248 "--no-input", 

249 dest="no_input", 

250 action="store_true", 

251 default=False, 

252 help="Disable prompting for input.", 

253) 

254 

255keyring_provider: Callable[..., Option] = partial( 

256 Option, 

257 "--keyring-provider", 

258 dest="keyring_provider", 

259 choices=["auto", "disabled", "import", "subprocess"], 

260 default="auto", 

261 help=( 

262 "Enable the credential lookup via the keyring library if user input is allowed." 

263 " Specify which mechanism to use [disabled, import, subprocess]." 

264 " (default: disabled)" 

265 ), 

266) 

267 

268proxy: Callable[..., Option] = partial( 

269 Option, 

270 "--proxy", 

271 dest="proxy", 

272 type="str", 

273 default="", 

274 help="Specify a proxy in the form scheme://[user:passwd@]proxy.server:port.", 

275) 

276 

277retries: Callable[..., Option] = partial( 

278 Option, 

279 "--retries", 

280 dest="retries", 

281 type="int", 

282 default=5, 

283 help="Maximum number of retries each connection should attempt " 

284 "(default %default times).", 

285) 

286 

287timeout: Callable[..., Option] = partial( 

288 Option, 

289 "--timeout", 

290 "--default-timeout", 

291 metavar="sec", 

292 dest="timeout", 

293 type="float", 

294 default=15, 

295 help="Set the socket timeout (default %default seconds).", 

296) 

297 

298 

299def exists_action() -> Option: 

300 return Option( 

301 # Option when path already exist 

302 "--exists-action", 

303 dest="exists_action", 

304 type="choice", 

305 choices=["s", "i", "w", "b", "a"], 

306 default=[], 

307 action="append", 

308 metavar="action", 

309 help="Default action when a path already exists: " 

310 "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.", 

311 ) 

312 

313 

314cert: Callable[..., Option] = partial( 

315 PipOption, 

316 "--cert", 

317 dest="cert", 

318 type="path", 

319 metavar="path", 

320 help=( 

321 "Path to PEM-encoded CA certificate bundle. " 

322 "If provided, overrides the default. " 

323 "See 'SSL Certificate Verification' in pip documentation " 

324 "for more information." 

325 ), 

326) 

327 

328client_cert: Callable[..., Option] = partial( 

329 PipOption, 

330 "--client-cert", 

331 dest="client_cert", 

332 type="path", 

333 default=None, 

334 metavar="path", 

335 help="Path to SSL client certificate, a single file containing the " 

336 "private key and the certificate in PEM format.", 

337) 

338 

339index_url: Callable[..., Option] = partial( 

340 Option, 

341 "-i", 

342 "--index-url", 

343 "--pypi-url", 

344 dest="index_url", 

345 metavar="URL", 

346 default=PyPI.simple_url, 

347 help="Base URL of the Python Package Index (default %default). " 

348 "This should point to a repository compliant with PEP 503 " 

349 "(the simple repository API) or a local directory laid out " 

350 "in the same format.", 

351) 

352 

353 

354def extra_index_url() -> Option: 

355 return Option( 

356 "--extra-index-url", 

357 dest="extra_index_urls", 

358 metavar="URL", 

359 action="append", 

360 default=[], 

361 help="Extra URLs of package indexes to use in addition to " 

362 "--index-url. Should follow the same rules as " 

363 "--index-url.", 

364 ) 

365 

366 

367no_index: Callable[..., Option] = partial( 

368 Option, 

369 "--no-index", 

370 dest="no_index", 

371 action="store_true", 

372 default=False, 

373 help="Ignore package index (only looking at --find-links URLs instead).", 

374) 

375 

376 

377def find_links() -> Option: 

378 return Option( 

379 "-f", 

380 "--find-links", 

381 dest="find_links", 

382 action="append", 

383 default=[], 

384 metavar="url", 

385 help="If a URL or path to an html file, then parse for links to " 

386 "archives such as sdist (.tar.gz) or wheel (.whl) files. " 

387 "If a local path or file:// URL that's a directory, " 

388 "then look for archives in the directory listing. " 

389 "Links to VCS project URLs are not supported.", 

390 ) 

391 

392 

393def trusted_host() -> Option: 

394 return Option( 

395 "--trusted-host", 

396 dest="trusted_hosts", 

397 action="append", 

398 metavar="HOSTNAME", 

399 default=[], 

400 help="Mark this host or host:port pair as trusted, even though it " 

401 "does not have valid or any HTTPS.", 

402 ) 

403 

404 

405def constraints() -> Option: 

406 return Option( 

407 "-c", 

408 "--constraint", 

409 dest="constraints", 

410 action="append", 

411 default=[], 

412 metavar="file", 

413 help="Constrain versions using the given constraints file. " 

414 "This option can be used multiple times.", 

415 ) 

416 

417 

418def requirements() -> Option: 

419 return Option( 

420 "-r", 

421 "--requirement", 

422 dest="requirements", 

423 action="append", 

424 default=[], 

425 metavar="file", 

426 help="Install from the given requirements file. " 

427 "This option can be used multiple times.", 

428 ) 

429 

430 

431def editable() -> Option: 

432 return Option( 

433 "-e", 

434 "--editable", 

435 dest="editables", 

436 action="append", 

437 default=[], 

438 metavar="path/url", 

439 help=( 

440 "Install a project in editable mode (i.e. setuptools " 

441 '"develop mode") from a local project path or a VCS url.' 

442 ), 

443 ) 

444 

445 

446def _handle_src(option: Option, opt_str: str, value: str, parser: OptionParser) -> None: 

447 value = os.path.abspath(value) 

448 setattr(parser.values, option.dest, value) 

449 

450 

451src: Callable[..., Option] = partial( 

452 PipOption, 

453 "--src", 

454 "--source", 

455 "--source-dir", 

456 "--source-directory", 

457 dest="src_dir", 

458 type="path", 

459 metavar="dir", 

460 default=get_src_prefix(), 

461 action="callback", 

462 callback=_handle_src, 

463 help="Directory to check out editable projects into. " 

464 'The default in a virtualenv is "<venv path>/src". ' 

465 'The default for global installs is "<current dir>/src".', 

466) 

467 

468 

469def _get_format_control(values: Values, option: Option) -> Any: 

470 """Get a format_control object.""" 

471 return getattr(values, option.dest) 

472 

473 

474def _handle_no_binary( 

475 option: Option, opt_str: str, value: str, parser: OptionParser 

476) -> None: 

477 existing = _get_format_control(parser.values, option) 

478 FormatControl.handle_mutual_excludes( 

479 value, 

480 existing.no_binary, 

481 existing.only_binary, 

482 ) 

483 

484 

485def _handle_only_binary( 

486 option: Option, opt_str: str, value: str, parser: OptionParser 

487) -> None: 

488 existing = _get_format_control(parser.values, option) 

489 FormatControl.handle_mutual_excludes( 

490 value, 

491 existing.only_binary, 

492 existing.no_binary, 

493 ) 

494 

495 

496def no_binary() -> Option: 

497 format_control = FormatControl(set(), set()) 

498 return Option( 

499 "--no-binary", 

500 dest="format_control", 

501 action="callback", 

502 callback=_handle_no_binary, 

503 type="str", 

504 default=format_control, 

505 help="Do not use binary packages. Can be supplied multiple times, and " 

506 'each time adds to the existing value. Accepts either ":all:" to ' 

507 'disable all binary packages, ":none:" to empty the set (notice ' 

508 "the colons), or one or more package names with commas between " 

509 "them (no colons). Note that some packages are tricky to compile " 

510 "and may fail to install when this option is used on them.", 

511 ) 

512 

513 

514def only_binary() -> Option: 

515 format_control = FormatControl(set(), set()) 

516 return Option( 

517 "--only-binary", 

518 dest="format_control", 

519 action="callback", 

520 callback=_handle_only_binary, 

521 type="str", 

522 default=format_control, 

523 help="Do not use source packages. Can be supplied multiple times, and " 

524 'each time adds to the existing value. Accepts either ":all:" to ' 

525 'disable all source packages, ":none:" to empty the set, or one ' 

526 "or more package names with commas between them. Packages " 

527 "without binary distributions will fail to install when this " 

528 "option is used on them.", 

529 ) 

530 

531 

532platforms: Callable[..., Option] = partial( 

533 Option, 

534 "--platform", 

535 dest="platforms", 

536 metavar="platform", 

537 action="append", 

538 default=None, 

539 help=( 

540 "Only use wheels compatible with <platform>. Defaults to the " 

541 "platform of the running system. Use this option multiple times to " 

542 "specify multiple platforms supported by the target interpreter." 

543 ), 

544) 

545 

546 

547# This was made a separate function for unit-testing purposes. 

548def _convert_python_version(value: str) -> Tuple[Tuple[int, ...], Optional[str]]: 

549 """ 

550 Convert a version string like "3", "37", or "3.7.3" into a tuple of ints. 

551 

552 :return: A 2-tuple (version_info, error_msg), where `error_msg` is 

553 non-None if and only if there was a parsing error. 

554 """ 

555 if not value: 

556 # The empty string is the same as not providing a value. 

557 return (None, None) 

558 

559 parts = value.split(".") 

560 if len(parts) > 3: 

561 return ((), "at most three version parts are allowed") 

562 

563 if len(parts) == 1: 

564 # Then we are in the case of "3" or "37". 

565 value = parts[0] 

566 if len(value) > 1: 

567 parts = [value[0], value[1:]] 

568 

569 try: 

570 version_info = tuple(int(part) for part in parts) 

571 except ValueError: 

572 return ((), "each version part must be an integer") 

573 

574 return (version_info, None) 

575 

576 

577def _handle_python_version( 

578 option: Option, opt_str: str, value: str, parser: OptionParser 

579) -> None: 

580 """ 

581 Handle a provided --python-version value. 

582 """ 

583 version_info, error_msg = _convert_python_version(value) 

584 if error_msg is not None: 

585 msg = "invalid --python-version value: {!r}: {}".format( 

586 value, 

587 error_msg, 

588 ) 

589 raise_option_error(parser, option=option, msg=msg) 

590 

591 parser.values.python_version = version_info 

592 

593 

594python_version: Callable[..., Option] = partial( 

595 Option, 

596 "--python-version", 

597 dest="python_version", 

598 metavar="python_version", 

599 action="callback", 

600 callback=_handle_python_version, 

601 type="str", 

602 default=None, 

603 help=dedent( 

604 """\ 

605 The Python interpreter version to use for wheel and "Requires-Python" 

606 compatibility checks. Defaults to a version derived from the running 

607 interpreter. The version can be specified using up to three dot-separated 

608 integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor 

609 version can also be given as a string without dots (e.g. "37" for 3.7.0). 

610 """ 

611 ), 

612) 

613 

614 

615implementation: Callable[..., Option] = partial( 

616 Option, 

617 "--implementation", 

618 dest="implementation", 

619 metavar="implementation", 

620 default=None, 

621 help=( 

622 "Only use wheels compatible with Python " 

623 "implementation <implementation>, e.g. 'pp', 'jy', 'cp', " 

624 " or 'ip'. If not specified, then the current " 

625 "interpreter implementation is used. Use 'py' to force " 

626 "implementation-agnostic wheels." 

627 ), 

628) 

629 

630 

631abis: Callable[..., Option] = partial( 

632 Option, 

633 "--abi", 

634 dest="abis", 

635 metavar="abi", 

636 action="append", 

637 default=None, 

638 help=( 

639 "Only use wheels compatible with Python abi <abi>, e.g. 'pypy_41'. " 

640 "If not specified, then the current interpreter abi tag is used. " 

641 "Use this option multiple times to specify multiple abis supported " 

642 "by the target interpreter. Generally you will need to specify " 

643 "--implementation, --platform, and --python-version when using this " 

644 "option." 

645 ), 

646) 

647 

648 

649def add_target_python_options(cmd_opts: OptionGroup) -> None: 

650 cmd_opts.add_option(platforms()) 

651 cmd_opts.add_option(python_version()) 

652 cmd_opts.add_option(implementation()) 

653 cmd_opts.add_option(abis()) 

654 

655 

656def make_target_python(options: Values) -> TargetPython: 

657 target_python = TargetPython( 

658 platforms=options.platforms, 

659 py_version_info=options.python_version, 

660 abis=options.abis, 

661 implementation=options.implementation, 

662 ) 

663 

664 return target_python 

665 

666 

667def prefer_binary() -> Option: 

668 return Option( 

669 "--prefer-binary", 

670 dest="prefer_binary", 

671 action="store_true", 

672 default=False, 

673 help="Prefer older binary packages over newer source packages.", 

674 ) 

675 

676 

677cache_dir: Callable[..., Option] = partial( 

678 PipOption, 

679 "--cache-dir", 

680 dest="cache_dir", 

681 default=USER_CACHE_DIR, 

682 metavar="dir", 

683 type="path", 

684 help="Store the cache data in <dir>.", 

685) 

686 

687 

688def _handle_no_cache_dir( 

689 option: Option, opt: str, value: str, parser: OptionParser 

690) -> None: 

691 """ 

692 Process a value provided for the --no-cache-dir option. 

693 

694 This is an optparse.Option callback for the --no-cache-dir option. 

695 """ 

696 # The value argument will be None if --no-cache-dir is passed via the 

697 # command-line, since the option doesn't accept arguments. However, 

698 # the value can be non-None if the option is triggered e.g. by an 

699 # environment variable, like PIP_NO_CACHE_DIR=true. 

700 if value is not None: 

701 # Then parse the string value to get argument error-checking. 

702 try: 

703 strtobool(value) 

704 except ValueError as exc: 

705 raise_option_error(parser, option=option, msg=str(exc)) 

706 

707 # Originally, setting PIP_NO_CACHE_DIR to a value that strtobool() 

708 # converted to 0 (like "false" or "no") caused cache_dir to be disabled 

709 # rather than enabled (logic would say the latter). Thus, we disable 

710 # the cache directory not just on values that parse to True, but (for 

711 # backwards compatibility reasons) also on values that parse to False. 

712 # In other words, always set it to False if the option is provided in 

713 # some (valid) form. 

714 parser.values.cache_dir = False 

715 

716 

717no_cache: Callable[..., Option] = partial( 

718 Option, 

719 "--no-cache-dir", 

720 dest="cache_dir", 

721 action="callback", 

722 callback=_handle_no_cache_dir, 

723 help="Disable the cache.", 

724) 

725 

726no_deps: Callable[..., Option] = partial( 

727 Option, 

728 "--no-deps", 

729 "--no-dependencies", 

730 dest="ignore_dependencies", 

731 action="store_true", 

732 default=False, 

733 help="Don't install package dependencies.", 

734) 

735 

736ignore_requires_python: Callable[..., Option] = partial( 

737 Option, 

738 "--ignore-requires-python", 

739 dest="ignore_requires_python", 

740 action="store_true", 

741 help="Ignore the Requires-Python information.", 

742) 

743 

744no_build_isolation: Callable[..., Option] = partial( 

745 Option, 

746 "--no-build-isolation", 

747 dest="build_isolation", 

748 action="store_false", 

749 default=True, 

750 help="Disable isolation when building a modern source distribution. " 

751 "Build dependencies specified by PEP 518 must be already installed " 

752 "if this option is used.", 

753) 

754 

755check_build_deps: Callable[..., Option] = partial( 

756 Option, 

757 "--check-build-dependencies", 

758 dest="check_build_deps", 

759 action="store_true", 

760 default=False, 

761 help="Check the build dependencies when PEP517 is used.", 

762) 

763 

764 

765def _handle_no_use_pep517( 

766 option: Option, opt: str, value: str, parser: OptionParser 

767) -> None: 

768 """ 

769 Process a value provided for the --no-use-pep517 option. 

770 

771 This is an optparse.Option callback for the no_use_pep517 option. 

772 """ 

773 # Since --no-use-pep517 doesn't accept arguments, the value argument 

774 # will be None if --no-use-pep517 is passed via the command-line. 

775 # However, the value can be non-None if the option is triggered e.g. 

776 # by an environment variable, for example "PIP_NO_USE_PEP517=true". 

777 if value is not None: 

778 msg = """A value was passed for --no-use-pep517, 

779 probably using either the PIP_NO_USE_PEP517 environment variable 

780 or the "no-use-pep517" config file option. Use an appropriate value 

781 of the PIP_USE_PEP517 environment variable or the "use-pep517" 

782 config file option instead. 

783 """ 

784 raise_option_error(parser, option=option, msg=msg) 

785 

786 # If user doesn't wish to use pep517, we check if setuptools and wheel are installed 

787 # and raise error if it is not. 

788 packages = ("setuptools", "wheel") 

789 if not all(importlib.util.find_spec(package) for package in packages): 

790 msg = ( 

791 f"It is not possible to use --no-use-pep517 " 

792 f"without {' and '.join(packages)} installed." 

793 ) 

794 raise_option_error(parser, option=option, msg=msg) 

795 

796 # Otherwise, --no-use-pep517 was passed via the command-line. 

797 parser.values.use_pep517 = False 

798 

799 

800use_pep517: Any = partial( 

801 Option, 

802 "--use-pep517", 

803 dest="use_pep517", 

804 action="store_true", 

805 default=None, 

806 help="Use PEP 517 for building source distributions " 

807 "(use --no-use-pep517 to force legacy behaviour).", 

808) 

809 

810no_use_pep517: Any = partial( 

811 Option, 

812 "--no-use-pep517", 

813 dest="use_pep517", 

814 action="callback", 

815 callback=_handle_no_use_pep517, 

816 default=None, 

817 help=SUPPRESS_HELP, 

818) 

819 

820 

821def _handle_config_settings( 

822 option: Option, opt_str: str, value: str, parser: OptionParser 

823) -> None: 

824 key, sep, val = value.partition("=") 

825 if sep != "=": 

826 parser.error(f"Arguments to {opt_str} must be of the form KEY=VAL") # noqa 

827 dest = getattr(parser.values, option.dest) 

828 if dest is None: 

829 dest = {} 

830 setattr(parser.values, option.dest, dest) 

831 if key in dest: 

832 if isinstance(dest[key], list): 

833 dest[key].append(val) 

834 else: 

835 dest[key] = [dest[key], val] 

836 else: 

837 dest[key] = val 

838 

839 

840config_settings: Callable[..., Option] = partial( 

841 Option, 

842 "-C", 

843 "--config-settings", 

844 dest="config_settings", 

845 type=str, 

846 action="callback", 

847 callback=_handle_config_settings, 

848 metavar="settings", 

849 help="Configuration settings to be passed to the PEP 517 build backend. " 

850 "Settings take the form KEY=VALUE. Use multiple --config-settings options " 

851 "to pass multiple keys to the backend.", 

852) 

853 

854build_options: Callable[..., Option] = partial( 

855 Option, 

856 "--build-option", 

857 dest="build_options", 

858 metavar="options", 

859 action="append", 

860 help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", 

861) 

862 

863global_options: Callable[..., Option] = partial( 

864 Option, 

865 "--global-option", 

866 dest="global_options", 

867 action="append", 

868 metavar="options", 

869 help="Extra global options to be supplied to the setup.py " 

870 "call before the install or bdist_wheel command.", 

871) 

872 

873no_clean: Callable[..., Option] = partial( 

874 Option, 

875 "--no-clean", 

876 action="store_true", 

877 default=False, 

878 help="Don't clean up build directories.", 

879) 

880 

881pre: Callable[..., Option] = partial( 

882 Option, 

883 "--pre", 

884 action="store_true", 

885 default=False, 

886 help="Include pre-release and development versions. By default, " 

887 "pip only finds stable versions.", 

888) 

889 

890disable_pip_version_check: Callable[..., Option] = partial( 

891 Option, 

892 "--disable-pip-version-check", 

893 dest="disable_pip_version_check", 

894 action="store_true", 

895 default=False, 

896 help="Don't periodically check PyPI to determine whether a new version " 

897 "of pip is available for download. Implied with --no-index.", 

898) 

899 

900root_user_action: Callable[..., Option] = partial( 

901 Option, 

902 "--root-user-action", 

903 dest="root_user_action", 

904 default="warn", 

905 choices=["warn", "ignore"], 

906 help="Action if pip is run as a root user. By default, a warning message is shown.", 

907) 

908 

909 

910def _handle_merge_hash( 

911 option: Option, opt_str: str, value: str, parser: OptionParser 

912) -> None: 

913 """Given a value spelled "algo:digest", append the digest to a list 

914 pointed to in a dict by the algo name.""" 

915 if not parser.values.hashes: 

916 parser.values.hashes = {} 

917 try: 

918 algo, digest = value.split(":", 1) 

919 except ValueError: 

920 parser.error( 

921 "Arguments to {} must be a hash name " # noqa 

922 "followed by a value, like --hash=sha256:" 

923 "abcde...".format(opt_str) 

924 ) 

925 if algo not in STRONG_HASHES: 

926 parser.error( 

927 "Allowed hash algorithms for {} are {}.".format( # noqa 

928 opt_str, ", ".join(STRONG_HASHES) 

929 ) 

930 ) 

931 parser.values.hashes.setdefault(algo, []).append(digest) 

932 

933 

934hash: Callable[..., Option] = partial( 

935 Option, 

936 "--hash", 

937 # Hash values eventually end up in InstallRequirement.hashes due to 

938 # __dict__ copying in process_line(). 

939 dest="hashes", 

940 action="callback", 

941 callback=_handle_merge_hash, 

942 type="string", 

943 help="Verify that the package's archive matches this " 

944 "hash before installing. Example: --hash=sha256:abcdef...", 

945) 

946 

947 

948require_hashes: Callable[..., Option] = partial( 

949 Option, 

950 "--require-hashes", 

951 dest="require_hashes", 

952 action="store_true", 

953 default=False, 

954 help="Require a hash to check each requirement against, for " 

955 "repeatable installs. This option is implied when any package in a " 

956 "requirements file has a --hash option.", 

957) 

958 

959 

960list_path: Callable[..., Option] = partial( 

961 PipOption, 

962 "--path", 

963 dest="path", 

964 type="path", 

965 action="append", 

966 help="Restrict to the specified installation path for listing " 

967 "packages (can be used multiple times).", 

968) 

969 

970 

971def check_list_path_option(options: Values) -> None: 

972 if options.path and (options.user or options.local): 

973 raise CommandError("Cannot combine '--path' with '--user' or '--local'") 

974 

975 

976list_exclude: Callable[..., Option] = partial( 

977 PipOption, 

978 "--exclude", 

979 dest="excludes", 

980 action="append", 

981 metavar="package", 

982 type="package_name", 

983 help="Exclude specified package from the output", 

984) 

985 

986 

987no_python_version_warning: Callable[..., Option] = partial( 

988 Option, 

989 "--no-python-version-warning", 

990 dest="no_python_version_warning", 

991 action="store_true", 

992 default=False, 

993 help="Silence deprecation warnings for upcoming unsupported Pythons.", 

994) 

995 

996 

997# Features that are now always on. A warning is printed if they are used. 

998ALWAYS_ENABLED_FEATURES = [ 

999 "no-binary-enable-wheel-cache", # always on since 23.1 

1000] 

1001 

1002use_new_feature: Callable[..., Option] = partial( 

1003 Option, 

1004 "--use-feature", 

1005 dest="features_enabled", 

1006 metavar="feature", 

1007 action="append", 

1008 default=[], 

1009 choices=[ 

1010 "fast-deps", 

1011 "truststore", 

1012 ] 

1013 + ALWAYS_ENABLED_FEATURES, 

1014 help="Enable new functionality, that may be backward incompatible.", 

1015) 

1016 

1017use_deprecated_feature: Callable[..., Option] = partial( 

1018 Option, 

1019 "--use-deprecated", 

1020 dest="deprecated_features_enabled", 

1021 metavar="feature", 

1022 action="append", 

1023 default=[], 

1024 choices=[ 

1025 "legacy-resolver", 

1026 ], 

1027 help=("Enable deprecated functionality, that will be removed in the future."), 

1028) 

1029 

1030 

1031########## 

1032# groups # 

1033########## 

1034 

1035general_group: Dict[str, Any] = { 

1036 "name": "General Options", 

1037 "options": [ 

1038 help_, 

1039 debug_mode, 

1040 isolated_mode, 

1041 require_virtualenv, 

1042 python, 

1043 verbose, 

1044 version, 

1045 quiet, 

1046 log, 

1047 no_input, 

1048 keyring_provider, 

1049 proxy, 

1050 retries, 

1051 timeout, 

1052 exists_action, 

1053 trusted_host, 

1054 cert, 

1055 client_cert, 

1056 cache_dir, 

1057 no_cache, 

1058 disable_pip_version_check, 

1059 no_color, 

1060 no_python_version_warning, 

1061 use_new_feature, 

1062 use_deprecated_feature, 

1063 ], 

1064} 

1065 

1066index_group: Dict[str, Any] = { 

1067 "name": "Package Index Options", 

1068 "options": [ 

1069 index_url, 

1070 extra_index_url, 

1071 no_index, 

1072 find_links, 

1073 ], 

1074}