| Viewing file:  baseparser.py (10.22 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
"""Base option parser setup"""from __future__ import absolute_import
 
 import sys
 import optparse
 import os
 import re
 import textwrap
 from distutils.util import strtobool
 
 from pip._vendor.six import string_types
 from pip._vendor.six.moves import configparser
 from pip.locations import (
 legacy_config_file, config_basename, running_under_virtualenv,
 site_config_files
 )
 from pip.utils import appdirs, get_terminal_size
 
 
 _environ_prefix_re = re.compile(r"^PIP_", re.I)
 
 
 class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
 """A prettier/less verbose help formatter for optparse."""
 
 def __init__(self, *args, **kwargs):
 # help position must be aligned with __init__.parseopts.description
 kwargs['max_help_position'] = 30
 kwargs['indent_increment'] = 1
 kwargs['width'] = get_terminal_size()[0] - 2
 optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs)
 
 def format_option_strings(self, option):
 return self._format_option_strings(option, ' <%s>', ', ')
 
 def _format_option_strings(self, option, mvarfmt=' <%s>', optsep=', '):
 """
 Return a comma-separated list of option strings and metavars.
 
 :param option:  tuple of (short opt, long opt), e.g: ('-f', '--format')
 :param mvarfmt: metavar format string - evaluated as mvarfmt % metavar
 :param optsep:  separator
 """
 opts = []
 
 if option._short_opts:
 opts.append(option._short_opts[0])
 if option._long_opts:
 opts.append(option._long_opts[0])
 if len(opts) > 1:
 opts.insert(1, optsep)
 
 if option.takes_value():
 metavar = option.metavar or option.dest.lower()
 opts.append(mvarfmt % metavar.lower())
 
 return ''.join(opts)
 
 def format_heading(self, heading):
 if heading == 'Options':
 return ''
 return heading + ':\n'
 
 def format_usage(self, usage):
 """
 Ensure there is only one newline between usage and the first heading
 if there is no description.
 """
 msg = '\nUsage: %s\n' % self.indent_lines(textwrap.dedent(usage), "  ")
 return msg
 
 def format_description(self, description):
 # leave full control over description to us
 if description:
 if hasattr(self.parser, 'main'):
 label = 'Commands'
 else:
 label = 'Description'
 # some doc strings have initial newlines, some don't
 description = description.lstrip('\n')
 # some doc strings have final newlines and spaces, some don't
 description = description.rstrip()
 # dedent, then reindent
 description = self.indent_lines(textwrap.dedent(description), "  ")
 description = '%s:\n%s\n' % (label, description)
 return description
 else:
 return ''
 
 def format_epilog(self, epilog):
 # leave full control over epilog to us
 if epilog:
 return epilog
 else:
 return ''
 
 def indent_lines(self, text, indent):
 new_lines = [indent + line for line in text.split('\n')]
 return "\n".join(new_lines)
 
 
 class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter):
 """Custom help formatter for use in ConfigOptionParser.
 
 This is updates the defaults before expanding them, allowing
 them to show up correctly in the help listing.
 """
 
 def expand_default(self, option):
 if self.parser is not None:
 self.parser._update_defaults(self.parser.defaults)
 return optparse.IndentedHelpFormatter.expand_default(self, option)
 
 
 class CustomOptionParser(optparse.OptionParser):
 def insert_option_group(self, idx, *args, **kwargs):
 """Insert an OptionGroup at a given position."""
 group = self.add_option_group(*args, **kwargs)
 
 self.option_groups.pop()
 self.option_groups.insert(idx, group)
 
 return group
 
 @property
 def option_list_all(self):
 """Get a list of all options, including those in option groups."""
 res = self.option_list[:]
 for i in self.option_groups:
 res.extend(i.option_list)
 
 return res
 
 
 class ConfigOptionParser(CustomOptionParser):
 """Custom option parser which updates its defaults by checking the
 configuration files and environmental variables"""
 
 isolated = False
 
 def __init__(self, *args, **kwargs):
 self.config = configparser.RawConfigParser()
 self.name = kwargs.pop('name')
 self.isolated = kwargs.pop("isolated", False)
 self.files = self.get_config_files()
 if self.files:
 self.config.read(self.files)
 assert self.name
 optparse.OptionParser.__init__(self, *args, **kwargs)
 
 def get_config_files(self):
 # the files returned by this method will be parsed in order with the
 # first files listed being overridden by later files in standard
 # ConfigParser fashion
 config_file = os.environ.get('PIP_CONFIG_FILE', False)
 if config_file == os.devnull:
 return []
 
 # at the base we have any site-wide configuration
 files = list(site_config_files)
 
 # per-user configuration next
 if not self.isolated:
 if config_file and os.path.exists(config_file):
 files.append(config_file)
 else:
 # This is the legacy config file, we consider it to be a lower
 # priority than the new file location.
 files.append(legacy_config_file)
 
 # This is the new config file, we consider it to be a higher
 # priority than the legacy file.
 files.append(
 os.path.join(
 appdirs.user_config_dir("pip"),
 config_basename,
 )
 )
 
 # finally virtualenv configuration first trumping others
 if running_under_virtualenv():
 venv_config_file = os.path.join(
 sys.prefix,
 config_basename,
 )
 if os.path.exists(venv_config_file):
 files.append(venv_config_file)
 
 return files
 
 def check_default(self, option, key, val):
 try:
 return option.check_value(key, val)
 except optparse.OptionValueError as exc:
 print("An error occurred during configuration: %s" % exc)
 sys.exit(3)
 
 def _update_defaults(self, defaults):
 """Updates the given defaults with values from the config files and
 the environ. Does a little special handling for certain types of
 options (lists)."""
 # Then go and look for the other sources of configuration:
 config = {}
 # 1. config files
 for section in ('global', self.name):
 config.update(
 self.normalize_keys(self.get_config_section(section))
 )
 # 2. environmental variables
 if not self.isolated:
 config.update(self.normalize_keys(self.get_environ_vars()))
 # Accumulate complex default state.
 self.values = optparse.Values(self.defaults)
 late_eval = set()
 # Then set the options with those values
 for key, val in config.items():
 # ignore empty values
 if not val:
 continue
 
 option = self.get_option(key)
 # Ignore options not present in this parser. E.g. non-globals put
 # in [global] by users that want them to apply to all applicable
 # commands.
 if option is None:
 continue
 
 if option.action in ('store_true', 'store_false', 'count'):
 val = strtobool(val)
 elif option.action == 'append':
 val = val.split()
 val = [self.check_default(option, key, v) for v in val]
 elif option.action == 'callback':
 late_eval.add(option.dest)
 opt_str = option.get_opt_string()
 val = option.convert_value(opt_str, val)
 # From take_action
 args = option.callback_args or ()
 kwargs = option.callback_kwargs or {}
 option.callback(option, opt_str, val, self, *args, **kwargs)
 else:
 val = self.check_default(option, key, val)
 
 defaults[option.dest] = val
 
 for key in late_eval:
 defaults[key] = getattr(self.values, key)
 self.values = None
 return defaults
 
 def normalize_keys(self, items):
 """Return a config dictionary with normalized keys regardless of
 whether the keys were specified in environment variables or in config
 files"""
 normalized = {}
 for key, val in items:
 key = key.replace('_', '-')
 if not key.startswith('--'):
 key = '--%s' % key  # only prefer long opts
 normalized[key] = val
 return normalized
 
 def get_config_section(self, name):
 """Get a section of a configuration"""
 if self.config.has_section(name):
 return self.config.items(name)
 return []
 
 def get_environ_vars(self):
 """Returns a generator with all environmental vars with prefix PIP_"""
 for key, val in os.environ.items():
 if _environ_prefix_re.search(key):
 yield (_environ_prefix_re.sub("", key).lower(), val)
 
 def get_default_values(self):
 """Overridding to make updating the defaults after instantiation of
 the option parser possible, _update_defaults() does the dirty work."""
 if not self.process_default_values:
 # Old, pre-Optik 1.5 behaviour.
 return optparse.Values(self.defaults)
 
 defaults = self._update_defaults(self.defaults.copy())  # ours
 for option in self._get_all_options():
 default = defaults.get(option.dest)
 if isinstance(default, string_types):
 opt_str = option.get_opt_string()
 defaults[option.dest] = option.check_value(opt_str, default)
 return optparse.Values(defaults)
 
 def error(self, msg):
 self.print_usage(sys.stderr)
 self.exit(2, "%s\n" % msg)
 
 |