text: import argparse
  from collections import OrderedDict
  import os
  import re
  import sys
  import types
  
  if sys.version_info >= (3, 0):
      from io import StringIO
  else:
      from StringIO import StringIO
  
  __version__ = "0.9.3"
  
  
  ACTION_TYPES_THAT_DONT_NEED_A_VALUE = {argparse._StoreTrueAction,
      argparse._StoreFalseAction, argparse._CountAction,
      argparse._StoreConstAction, argparse._AppendConstAction}
  
  
  # global ArgumentParser instances
  _parsers = {}
  
  def initArgumentParser(name=None, **kwargs):
      """Creates a global ArgumentParser instance with the given name,
      passing any args other than "name" to the ArgumentParser constructor.
      This instance can then be retrieved using getArgumentParser(..)
      """
  
      if name is None:
          name = "default"
  
      if name in _parsers:
          raise ValueError(("kwargs besides 'name' can only be passed in the"
              " first time. '%s' ArgumentParser already exists: %s") % (
              name, _parsers[name]))
  
      kwargs.setdefault('formatter_class', argparse.ArgumentDefaultsHelpFormatter)
      kwargs.setdefault('conflict_handler', 'resolve')
      _parsers[name] = ArgumentParser(**kwargs)
  
  
  def getArgumentParser(name=None, **kwargs):
      """Returns the global ArgumentParser instance with the given name. The 1st
      time this function is called, a new ArgumentParser instance will be created
      for the given name, and any args other than "name" will be passed on to the
      ArgumentParser constructor.
      """
      if name is None:
          name = "default"
  
      if len(kwargs) > 0 or name not in _parsers:
          initArgumentParser(name, **kwargs)
  
      return _parsers[name]
  
  
  
  class ArgumentDefaultsRawHelpFormatter(    
      argparse.ArgumentDefaultsHelpFormatter, 
      argparse.RawTextHelpFormatter,
      argparse.RawDescriptionHelpFormatter):
      """HelpFormatter that adds default values AND doesn't do line-wrapping"""
      pass
  
  
  class ArgumentParser(argparse.ArgumentParser):
      """Drop-in replacement for argparse.ArgumentParser that adds support for
      environment variables and .ini or .yaml-style config files.
      """
  
      def __init__(self,
          prog=None,
          usage=None,
          description=None,
          epilog=None,
          version=None,
          parents=[],
          formatter_class=argparse.HelpFormatter,
          prefix_chars='-',
          fromfile_prefix_chars=None,
          argument_default=None,
          conflict_handler='error',
          add_help=True,
  
          add_config_file_help=True,
          add_env_var_help=True,
  
          default_config_files=[],
          allow_unknown_config_file_keys=False,
  
          args_for_setting_config_path=[],
          config_arg_is_required=False,
          config_arg_help_message="config file path",
          ):
  
          """Supports all the same args as the argparse.ArgumentParser
          constructor, as well as the following additional args.
  
          Additional Args:
              add_config_file_help: Whether to add a description of config file
                  syntax to the help message.
              add_env_var_help: Whether to add something to the help message for
                  args that can be set through environment variables.
              default_config_files: When specified, this list of config files will
                  be parsed in order, with the values from each config file
                  taking precedence over pervious ones. This allows an application
                  to look for config files in multiple standard locations such as
                  the install directory, home directory, and current directory:
                  ["<install dir>/app_config.ini",
                  "~/.my_app_config.ini",
                  "./app_config.txt"]
              allow_unknown_config_file_keys: Whether unknown config file keys
                  should be ignored or whether it should be an error.
              args_for_setting_config_path: A list of one or more command line
                  args that would allow a user to provide a config file path
                  (eg. ["-c", "--config-file"]). Default: []
              config_arg_is_required: when args_for_setting_config_path is set,
                  set this to True to always require users to provide a config path.
              config_arg_help_message: when args_for_setting_config_path is set,
                  this will be the help message for the config_file_args.
          """
          self._add_config_file_help = add_config_file_help
          self._add_env_var_help = add_env_var_help
  
          # extract kwargs that can be passed to the super constructor
          kwargs_for_super = {k: v for k, v in locals().items() if k in [
              "prog", "usage", "description", "epilog", "version", "parents",
              "formatter_class", "prefix_chars", "fromfile_prefix_chars",
              "argument_default", "conflict_handler", "add_help" ]}
          if sys.version_info >= (3, 3) and "version" in kwargs_for_super:
              del kwargs_for_super["version"]  # version arg deprecated in v3.3
  
          argparse.ArgumentParser.__init__(self, **kwargs_for_super)
  
          # parse the additionial args
          self._default_config_files = default_config_files
          self._allow_unknown_config_file_keys = allow_unknown_config_file_keys
          if args_for_setting_config_path:
              self.add_argument(*args_for_setting_config_path, dest="config_file",
                  required=config_arg_is_required, help=config_arg_help_message,
                  is_config_file=True)
  
  
      def parse_args(self, args = None, namespace = None,
                     config_file_contents = None, env_vars = os.environ):
          """Supports all the same args as the ArgumentParser.parse_args(..),
          as well as the following additional args.
  
          Additional Args:
              args: a list of args as in argparse, or a string (eg. "-x -y bla")
              config_file_contents: String. Used for testing.
              env_vars: Dictionary. Used for testing.
          """
          args, argv = self.parse_known_args(args = args,
              namespace = namespace,
              config_file_contents = config_file_contents,
              env_vars = env_vars)
          if argv:
              self.error('unrecognized arguments: %s' % ' '.join(argv))
          return args
  
  
      def parse_known_args(self, args = None, namespace = None,
                           config_file_contents = None, env_vars = os.environ):
          """Supports all the same args as the ArgumentParser.parse_args(..),
          as well as the following additional args.
  
          Additional Args:
              args: a list of args as in argparse, or a string (eg. "-x -y bla")
              config_file_contents: String. Used for testing.
              env_vars: Dictionary. Used for testing.
          """
  
          if args is None:
              args = sys.argv[1:]
          elif type(args) == str:
              args = args.split()
          else:
              args = list(args)
  
          # maps string describing the source (eg. env var) to a settings dict
          # to keep track of where values came from (used by print_values())
          self._source_to_settings = OrderedDict()
          self._command_line_args_string = ' '.join(args)
          if args:
              self._source_to_settings["Command Line Args: "] = {
                  '': self._command_line_args_string}
  
          # add env var settings to the command line that aren't there already
          env_var_args = []
          actions_with_env_var_values = [a for a in self._actions
              if a.option_strings and a.env_var
                  and a.env_var in env_vars
                  and not any(opt in args for opt in a.option_strings)]
          for a in actions_with_env_var_values:
              key = a.env_var
              value = env_vars[key]
              env_var_args += self.convert_setting_to_command_line_arg(
                  a, key, value)
  
          args = env_var_args + args
  
          if env_var_args:
              self._source_to_settings["Environment Variables:\n"] = OrderedDict(
                  [(a.env_var, env_vars[a.env_var])
                      for a in actions_with_env_var_values])
  
  
          # read settings from config file(s)
          if config_file_contents:
              stream = StringIO(config_file_contents)
              stream.name = "method arg"
              config_streams = [stream]
          else:
              config_streams = self._open_config_files(args)
  
          # add config file settings to the command line that aren't there already
  
          # for each action, add its possible config keys to a dict
          possible_config_keys = {config_key: action for action in self._actions
              for config_key in self.get_possible_config_keys(action)}
  
          # parse each config file
          for stream in config_streams[::-1]:
              try:
                  config_settings = self.parse_config_file(stream)
              finally:
                  if hasattr(stream, "close"):
                      stream.close()
              # make sure config file doesn't use any unknown keys
              if not self._allow_unknown_config_file_keys:
                  invalid_keys = list(
                      set(config_settings.keys()) - set(possible_config_keys.keys()))
                  if invalid_keys:
                      self.error(("%s contains unknown config key(s): %s") % (
                          stream.name, ", ".join(invalid_keys)))
  
              # add config settings to the command line if they aren't there already
              config_args = []
              for key, value in config_settings.items():
                  if key in possible_config_keys:
                      action = possible_config_keys[key]
                      already_on_command_line = any(
                          arg in args for arg in action.option_strings)
                      if already_on_command_line:
                          del config_settings[key]
                      else:
                          config_args += self.convert_setting_to_command_line_arg(
                              action, key, value)
  
              args = config_args + args
  
              if config_args:
                  self._source_to_settings[
                      "Config File (%s):\n" %stream.name]=config_settings
  
          # save default settings for use by print_values()
          default_settings = OrderedDict()
          for a in self._actions:
              already_on_command_line = any(arg in args for arg in a.option_strings)
              cares_about_default = a.option_strings or a.nargs in [
                  argparse.OPTIONAL, argparse.ZERO_OR_MORE]
              if (already_on_command_line or not cares_about_default or
                  a.default == None or a.default == argparse.SUPPRESS or
                  type(a) in ACTION_TYPES_THAT_DONT_NEED_A_VALUE):
                  continue
              else:
                  key = a.option_strings[-1] if a.option_strings else a.dest
                  default_settings[key] = str(a.default)
  
          if default_settings:
              self._source_to_settings["Defaults:\n"] = default_settings
  
          # parse all args (including command-line, config file, and env var)
          return argparse.ArgumentParser.parse_known_args(
              self, args=args, namespace=namespace)
  
      def parse_config_file(self, stream):
          """Parses a config file and return a dictionary of settings"""
  
          settings = OrderedDict()
          for i, line in enumerate(stream):
              line = line.strip()
              if not line or line[0] in ["#", ";", "["] or line.startswith("---"):
                  continue
              white_space = "\\s*"
              key = "(?P<key>[^:=;#\s]+?)"
              value1 = white_space+"[:=]"+white_space+"(?P<value>[^;#]+?)"
              value2 = white_space+"[\s]"+white_space+"(?P<value>[^;#\s]+?)"
              comment = white_space+"(?P<comment>\\s[;#].*)?"
  
              key_only_match = re.match("^" + key + comment +"$", line)
              if key_only_match:
                  key = key_only_match.group("key")
                  settings[key] = "true"
                  continue
  
              key_value_match = re.match("^"+key+value1+comment+"$", line) or \
                                  re.match("^"+key+value2+comment+"$", line)
              if key_value_match:
                  key = key_value_match.group("key")
                  value = key_value_match.group("value")
                  settings[key] = value
                  continue
  
              self.error("Unexpected line %s in %s: %s" % (i, stream.name, line))
          return settings
  
      def convert_setting_to_command_line_arg(self, action, key, value):
          """Converts a config file or env var key/value to a list of
          command line args to append to the command line.
  
          Args:
              action: The action corresponding to this setting
              key: The config file key or env var name (used for error messages)
              value: The raw value string from the config file or env var
          """
          assert type(value) == str
  
          args = []
          if value.lower() == "true":
              if type(action) not in ACTION_TYPES_THAT_DONT_NEED_A_VALUE:
                  self.error("%s set to 'True' rather than a value" % key)
              args.append( action.option_strings[-1] )
          elif value.startswith("[") and value.endswith("]"):
              if type(action) != argparse._AppendAction:
                  self.error(("%s can't be set to a list '%s' unless its action "
                      "type is changed to 'append'") % (key, value))
              for list_elem in value[1:-1].split(","):
                  args.append( action.option_strings[-1] )
                  args.append( list_elem.strip() )
          else:
              if type(action) in ACTION_TYPES_THAT_DONT_NEED_A_VALUE:
                  self.error("%s is a flag but is being set to '%s'" % (key,
                                                                        value))
              args.append( action.option_strings[-1] )
              args.append( value )
          return args
  
      def get_possible_config_keys(self, action):
          """This method decides which actions can be set in a config file and
          what their keys will be. It return a list of 0 or more config keys that
          can be used to set the given action's value in a config file.
          """
          keys = []
          for arg in action.option_strings:
              if arg.startswith(2*self.prefix_chars[0]):
                  keys += [arg[2:], arg] # eg. for '--bla' return ['bla', '--bla']
  
          return keys
  
  
      def _open_config_files(self, command_line_args):
          """Tries to parse config file path(s) from within command_line_args. 
          Returns a list of opened config files, including files specified on the 
          command line as well as any default_config_files specified in the 
          constructor that are present on disk.
  
          Args:
              command_line_args: List of all args (already split on spaces)
          """
          # open any default config files
          config_files = [open(f) for f in map(
              os.path.expanduser, self._default_config_files) if os.path.isfile(f)]
  
          if not command_line_args:
              return config_files
  
          # list actions which had is_config_file=True set. Its possible there is 
          # more than one such arg (perhaps to have multiple aliases for the file) 
          user_config_file_arg_actions = [
              a for a in self._actions if getattr(a, "is_config_file", False)]
  
          if not user_config_file_arg_actions:
              return config_files
  
          for action in user_config_file_arg_actions:
              # try to parse out the config file path by using a clean new
              # ArgumentParser that only knows this one arg/action.
              arg_parser = argparse.ArgumentParser(
                  prefix_chars=self.prefix_chars,
                  add_help=False)
  
              arg_parser._add_action(action)
  
              # make parser not exit on error by replacing its error method.
              # Otherwise it sys.exits(..) if, for example, config file 
              # is_required=True and user doesn't provide it.
              def error_method(self, message):
                  pass
              arg_parser.error = types.MethodType(error_method, arg_parser)
  
              # check whether the user provided a value 
              parsed_arg = arg_parser.parse_known_args(args=command_line_args)
              if not parsed_arg:
                  continue
              namespace, _ = parsed_arg
              user_config_file = getattr(namespace, action.dest, None)
              if not user_config_file:
                  continue
              # validate the user-provided config file path
              user_config_file = os.path.expanduser(user_config_file)
              if not os.path.isfile(user_config_file):
                  self.error('File not found: %s' % user_config_file)
  
              config_files += [open(user_config_file)]
  
          return config_files
  
      def format_values(self):
          """Returns a string with all args and settings and where they came from
          (eg. command line, config file, enviroment variable or default)
          """
  
          r = StringIO()
          for source, settings in self._source_to_settings.items():
              r.write(source)
              for key, value in settings.items():
                  if key:
                      r.write("  %-19s%s\n" % (key+":", value))
                  else:
                      r.write("  %s\n" % value)
  
          return r.getvalue()
  
      def print_values(self, file = sys.stdout):
          """Prints the format_values() string (to sys.stdout or another file)."""
          file.write(self.format_values())
  
      def format_help(self):
          msg = ""
          added_config_file_help = False
          added_env_var_help = False
          if self._add_config_file_help:
              default_config_files = self._default_config_files
              cc = 2*self.prefix_chars[0]  # eg. --
              config_keys = [(arg, a) for a in self._actions for arg in
                  a.option_strings if arg.startswith(cc) and a.dest != "help"]
              config_path_actions = [a for a in
                  self._actions if getattr(a, "is_config_file", False)]
  
              if (default_config_files or config_path_actions) and config_keys:
                  self._add_config_file_help = False  # prevent duplication
                  added_config_file_help = True
  
                  msg += ("Args that start with '%s' (eg. %s) can also be set in "
                          "a config file") % (cc, config_keys[0][0])
                  config_arg_string = " or ".join(a.option_strings[0]
                      for a in config_path_actions if a.option_strings)
                  if config_arg_string:
                      config_arg_string = "specified via " + config_arg_string
                  if default_config_files or config_arg_string:
                      msg += " (%s)" % " or ".join(default_config_files +
                                                   [config_arg_string])
                  msg += " by using .ini or .yaml-style syntax "
                  examples = []
                  key_value_args = [arg for arg, a in config_keys
                      if a.type not in ACTION_TYPES_THAT_DONT_NEED_A_VALUE]
                  if key_value_args:
                      examples += ["%s=value" % key_value_args[0].strip(cc)]
                  flag_args = [arg for arg, a in config_keys
                      if a.type in ACTION_TYPES_THAT_DONT_NEED_A_VALUE]
                  if flag_args:
                      examples += ["%s=TRUE" % flag_args[0].strip(cc)]
                  if examples:
                      msg += "(eg. %s)." % " or ".join(examples)
  
          if self._add_env_var_help:
              env_var_actions = [(a.env_var, a) for a in self._actions
                                 if getattr(a, "env_var", None)]
              for env_var, a in env_var_actions:
                  env_var_help_string = "   [env var: %s]" % env_var
                  if not a.help:
                      a.help = ""
                  if env_var_help_string not in a.help:
                      a.help += env_var_help_string
                      added_env_var_help = True
                      self._add_env_var_help = False  # prevent duplication
  
          if added_env_var_help or added_config_file_help:
              value_sources = ["defaults"]
              if added_config_file_help:
                  value_sources = ["config file values"] + value_sources
              if added_env_var_help:
                  value_sources = ["environment variables"] + value_sources
              msg += (" If an arg is specified in more than one place, then "
                  "command-line values override %s.") % (
                  " which override ".join(value_sources))
          if msg:
              self.description = (self.description or "") + " " + msg
  
          return argparse.ArgumentParser.format_help(self)
  
  
  
  def add_argument(self, *args, **kwargs):
      """
      This method supports the same args as ArgumentParser.add_argument(..)
      as well as the additional args below.
  
      All
      Additional Args:
          env_var: The name of the environment variable to check.
          is_config_file: If True, this arg is treated as a config file path
              This provides an alternative way to specify config files in place of
              the ArgumentParser(fromfile_prefix_chars=..) mechanism.
              Default: False
      """
  
      env_var = kwargs.pop("env_var", None)
      is_config_file = kwargs.pop("is_config_file", None)
  
      action = self.original_add_argument_method(*args, **kwargs)
  
      is_positional_arg = not action.option_strings
      if is_positional_arg and env_var:
          raise ValueError("env_var can't be set for a positional arg.")
      if is_config_file and type(action) != argparse._StoreAction:
          raise ValueError("arg with is_config_file=True must have action='store'")
  
      action.env_var = env_var
      action.is_config_file = is_config_file
  
      return action
  
  # wrap ArgumentParser's add_argument(..) method with the one above
  argparse._ActionsContainer.original_add_argument_method = argparse._ActionsContainer.add_argument
  argparse._ActionsContainer.add_argument = add_argument
  
  
  # add all public classes in argparse module's namespace to this namespace so 
  # that the 2 modules are truly interchangeable
  HelpFormatter = argparse.HelpFormatter
  RawDescriptionHelpFormatter = argparse.RawDescriptionHelpFormatter
  RawTextHelpFormatter = argparse.RawTextHelpFormatter
  ArgumentDefaultsHelpFormatter = argparse.ArgumentDefaultsHelpFormatter
  ArgumentError = argparse.ArgumentError
  ArgumentTypeError = argparse.ArgumentTypeError
  Action = argparse.Action
  FileType = argparse.FileType
  Namespace = argparse.Namespace
  
  
  # create shorter aliases for the key methods and class names
  getArgParser = getArgumentParser
  getParser = getArgumentParser
  
  ArgParser = ArgumentParser
  Parser = ArgumentParser
  
  argparse._ActionsContainer.add_arg = argparse._ActionsContainer.add_argument
  argparse._ActionsContainer.add = argparse._ActionsContainer.add_argument
  
  ArgumentParser.parse = ArgumentParser.parse_args
  ArgumentParser.parse_known = ArgumentParser.parse_known_args
  
  RawFormatter = RawDescriptionHelpFormatter
  DefaultsFormatter = ArgumentDefaultsHelpFormatter
  DefaultsRawFormatter = ArgumentDefaultsRawHelpFormatter
  
  