Path: blob/master/venv/Lib/site-packages/pip/_internal/cli/parser.py
811 views
"""Base option parser setup"""12# The following comment should be removed at some point in the future.3# mypy: disallow-untyped-defs=False45from __future__ import absolute_import67import logging8import optparse9import sys10import textwrap11from distutils.util import strtobool1213from pip._vendor.six import string_types1415from pip._internal.cli.status_codes import UNKNOWN_ERROR16from pip._internal.configuration import Configuration, ConfigurationError17from pip._internal.utils.compat import get_terminal_size1819logger = logging.getLogger(__name__)202122class PrettyHelpFormatter(optparse.IndentedHelpFormatter):23"""A prettier/less verbose help formatter for optparse."""2425def __init__(self, *args, **kwargs):26# help position must be aligned with __init__.parseopts.description27kwargs['max_help_position'] = 3028kwargs['indent_increment'] = 129kwargs['width'] = get_terminal_size()[0] - 230optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs)3132def format_option_strings(self, option):33return self._format_option_strings(option)3435def _format_option_strings(self, option, mvarfmt=' <{}>', optsep=', '):36"""37Return a comma-separated list of option strings and metavars.3839:param option: tuple of (short opt, long opt), e.g: ('-f', '--format')40:param mvarfmt: metavar format string41:param optsep: separator42"""43opts = []4445if option._short_opts:46opts.append(option._short_opts[0])47if option._long_opts:48opts.append(option._long_opts[0])49if len(opts) > 1:50opts.insert(1, optsep)5152if option.takes_value():53metavar = option.metavar or option.dest.lower()54opts.append(mvarfmt.format(metavar.lower()))5556return ''.join(opts)5758def format_heading(self, heading):59if heading == 'Options':60return ''61return heading + ':\n'6263def format_usage(self, usage):64"""65Ensure there is only one newline between usage and the first heading66if there is no description.67"""68msg = '\nUsage: {}\n'.format(69self.indent_lines(textwrap.dedent(usage), " "))70return msg7172def format_description(self, description):73# leave full control over description to us74if description:75if hasattr(self.parser, 'main'):76label = 'Commands'77else:78label = 'Description'79# some doc strings have initial newlines, some don't80description = description.lstrip('\n')81# some doc strings have final newlines and spaces, some don't82description = description.rstrip()83# dedent, then reindent84description = self.indent_lines(textwrap.dedent(description), " ")85description = '{}:\n{}\n'.format(label, description)86return description87else:88return ''8990def format_epilog(self, epilog):91# leave full control over epilog to us92if epilog:93return epilog94else:95return ''9697def indent_lines(self, text, indent):98new_lines = [indent + line for line in text.split('\n')]99return "\n".join(new_lines)100101102class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter):103"""Custom help formatter for use in ConfigOptionParser.104105This is updates the defaults before expanding them, allowing106them to show up correctly in the help listing.107"""108109def expand_default(self, option):110if self.parser is not None:111self.parser._update_defaults(self.parser.defaults)112return optparse.IndentedHelpFormatter.expand_default(self, option)113114115class CustomOptionParser(optparse.OptionParser):116117def insert_option_group(self, idx, *args, **kwargs):118"""Insert an OptionGroup at a given position."""119group = self.add_option_group(*args, **kwargs)120121self.option_groups.pop()122self.option_groups.insert(idx, group)123124return group125126@property127def option_list_all(self):128"""Get a list of all options, including those in option groups."""129res = self.option_list[:]130for i in self.option_groups:131res.extend(i.option_list)132133return res134135136class ConfigOptionParser(CustomOptionParser):137"""Custom option parser which updates its defaults by checking the138configuration files and environmental variables"""139140def __init__(self, *args, **kwargs):141self.name = kwargs.pop('name')142143isolated = kwargs.pop("isolated", False)144self.config = Configuration(isolated)145146assert self.name147optparse.OptionParser.__init__(self, *args, **kwargs)148149def check_default(self, option, key, val):150try:151return option.check_value(key, val)152except optparse.OptionValueError as exc:153print("An error occurred during configuration: {}".format(exc))154sys.exit(3)155156def _get_ordered_configuration_items(self):157# Configuration gives keys in an unordered manner. Order them.158override_order = ["global", self.name, ":env:"]159160# Pool the options into different groups161section_items = {name: [] for name in override_order}162for section_key, val in self.config.items():163# ignore empty values164if not val:165logger.debug(166"Ignoring configuration key '%s' as it's value is empty.",167section_key168)169continue170171section, key = section_key.split(".", 1)172if section in override_order:173section_items[section].append((key, val))174175# Yield each group in their override order176for section in override_order:177for key, val in section_items[section]:178yield key, val179180def _update_defaults(self, defaults):181"""Updates the given defaults with values from the config files and182the environ. Does a little special handling for certain types of183options (lists)."""184185# Accumulate complex default state.186self.values = optparse.Values(self.defaults)187late_eval = set()188# Then set the options with those values189for key, val in self._get_ordered_configuration_items():190# '--' because configuration supports only long names191option = self.get_option('--' + key)192193# Ignore options not present in this parser. E.g. non-globals put194# in [global] by users that want them to apply to all applicable195# commands.196if option is None:197continue198199if option.action in ('store_true', 'store_false', 'count'):200try:201val = strtobool(val)202except ValueError:203error_msg = invalid_config_error_message(204option.action, key, val205)206self.error(error_msg)207208elif option.action == 'append':209val = val.split()210val = [self.check_default(option, key, v) for v in val]211elif option.action == 'callback':212late_eval.add(option.dest)213opt_str = option.get_opt_string()214val = option.convert_value(opt_str, val)215# From take_action216args = option.callback_args or ()217kwargs = option.callback_kwargs or {}218option.callback(option, opt_str, val, self, *args, **kwargs)219else:220val = self.check_default(option, key, val)221222defaults[option.dest] = val223224for key in late_eval:225defaults[key] = getattr(self.values, key)226self.values = None227return defaults228229def get_default_values(self):230"""Overriding to make updating the defaults after instantiation of231the option parser possible, _update_defaults() does the dirty work."""232if not self.process_default_values:233# Old, pre-Optik 1.5 behaviour.234return optparse.Values(self.defaults)235236# Load the configuration, or error out in case of an error237try:238self.config.load()239except ConfigurationError as err:240self.exit(UNKNOWN_ERROR, str(err))241242defaults = self._update_defaults(self.defaults.copy()) # ours243for option in self._get_all_options():244default = defaults.get(option.dest)245if isinstance(default, string_types):246opt_str = option.get_opt_string()247defaults[option.dest] = option.check_value(opt_str, default)248return optparse.Values(defaults)249250def error(self, msg):251self.print_usage(sys.stderr)252self.exit(UNKNOWN_ERROR, "{}\n".format(msg))253254255def invalid_config_error_message(action, key, val):256"""Returns a better error message when invalid configuration option257is provided."""258if action in ('store_true', 'store_false'):259return ("{0} is not a valid value for {1} option, "260"please specify a boolean value like yes/no, "261"true/false or 1/0 instead.").format(val, key)262263return ("{0} is not a valid value for {1} option, "264"please specify a numerical value like 1/0 "265"instead.").format(val, key)266267268