github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/getopt.py (about)

     1  """Parser for command line options.
     2  
     3  This module helps scripts to parse the command line arguments in
     4  sys.argv.  It supports the same conventions as the Unix getopt()
     5  function (including the special meanings of arguments of the form `-'
     6  and `--').  Long options similar to those supported by GNU software
     7  may be used as well via an optional third argument.  This module
     8  provides two functions and an exception:
     9  
    10  getopt() -- Parse command line options
    11  gnu_getopt() -- Like getopt(), but allow option and non-option arguments
    12  to be intermixed.
    13  GetoptError -- exception (class) raised with 'opt' attribute, which is the
    14  option involved with the exception.
    15  """
    16  
    17  # Long option support added by Lars Wirzenius <liw@iki.fi>.
    18  #
    19  # Gerrit Holl <gerrit@nl.linux.org> moved the string-based exceptions
    20  # to class-based exceptions.
    21  #
    22  # Peter Astrand <astrand@lysator.liu.se> added gnu_getopt().
    23  #
    24  # TODO for gnu_getopt():
    25  #
    26  # - GNU getopt_long_only mechanism
    27  # - allow the caller to specify ordering
    28  # - RETURN_IN_ORDER option
    29  # - GNU extension with '-' as first character of option string
    30  # - optional arguments, specified by double colons
    31  # - an option string with a W followed by semicolon should
    32  #   treat "-W foo" as "--foo"
    33  
    34  __all__ = ["GetoptError","error","getopt","gnu_getopt"]
    35  
    36  import os
    37  
    38  class GetoptError(Exception):
    39      opt = ''
    40      msg = ''
    41      def __init__(self, msg, opt=''):
    42          self.msg = msg
    43          self.opt = opt
    44          Exception.__init__(self, msg, opt)
    45  
    46      def __str__(self):
    47          return self.msg
    48  
    49  error = GetoptError # backward compatibility
    50  
    51  def getopt(args, shortopts, longopts = []):
    52      """getopt(args, options[, long_options]) -> opts, args
    53  
    54      Parses command line options and parameter list.  args is the
    55      argument list to be parsed, without the leading reference to the
    56      running program.  Typically, this means "sys.argv[1:]".  shortopts
    57      is the string of option letters that the script wants to
    58      recognize, with options that require an argument followed by a
    59      colon (i.e., the same format that Unix getopt() uses).  If
    60      specified, longopts is a list of strings with the names of the
    61      long options which should be supported.  The leading '--'
    62      characters should not be included in the option name.  Options
    63      which require an argument should be followed by an equal sign
    64      ('=').
    65  
    66      The return value consists of two elements: the first is a list of
    67      (option, value) pairs; the second is the list of program arguments
    68      left after the option list was stripped (this is a trailing slice
    69      of the first argument).  Each option-and-value pair returned has
    70      the option as its first element, prefixed with a hyphen (e.g.,
    71      '-x'), and the option argument as its second element, or an empty
    72      string if the option has no argument.  The options occur in the
    73      list in the same order in which they were found, thus allowing
    74      multiple occurrences.  Long and short options may be mixed.
    75  
    76      """
    77  
    78      opts = []
    79      if type(longopts) == type(""):
    80          longopts = [longopts]
    81      else:
    82          longopts = list(longopts)
    83      while args and args[0].startswith('-') and args[0] != '-':
    84          if args[0] == '--':
    85              args = args[1:]
    86              break
    87          if args[0].startswith('--'):
    88              opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
    89          else:
    90              opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
    91  
    92      return opts, args
    93  
    94  def gnu_getopt(args, shortopts, longopts = []):
    95      """getopt(args, options[, long_options]) -> opts, args
    96  
    97      This function works like getopt(), except that GNU style scanning
    98      mode is used by default. This means that option and non-option
    99      arguments may be intermixed. The getopt() function stops
   100      processing options as soon as a non-option argument is
   101      encountered.
   102  
   103      If the first character of the option string is `+', or if the
   104      environment variable POSIXLY_CORRECT is set, then option
   105      processing stops as soon as a non-option argument is encountered.
   106  
   107      """
   108  
   109      opts = []
   110      prog_args = []
   111      if isinstance(longopts, str):
   112          longopts = [longopts]
   113      else:
   114          longopts = list(longopts)
   115  
   116      # Allow options after non-option arguments?
   117      if shortopts.startswith('+'):
   118          shortopts = shortopts[1:]
   119          all_options_first = True
   120      elif os.environ.get("POSIXLY_CORRECT"):
   121          all_options_first = True
   122      else:
   123          all_options_first = False
   124  
   125      while args:
   126          if args[0] == '--':
   127              prog_args += args[1:]
   128              break
   129  
   130          if args[0][:2] == '--':
   131              opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
   132          elif args[0][:1] == '-' and args[0] != '-':
   133              opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
   134          else:
   135              if all_options_first:
   136                  prog_args += args
   137                  break
   138              else:
   139                  prog_args.append(args[0])
   140                  args = args[1:]
   141  
   142      return opts, prog_args
   143  
   144  def do_longs(opts, opt, longopts, args):
   145      try:
   146          i = opt.index('=')
   147      except ValueError:
   148          optarg = None
   149      else:
   150          opt, optarg = opt[:i], opt[i+1:]
   151  
   152      has_arg, opt = long_has_args(opt, longopts)
   153      if has_arg:
   154          if optarg is None:
   155              if not args:
   156                  raise GetoptError('option --%s requires argument' % opt, opt)
   157              optarg, args = args[0], args[1:]
   158      elif optarg is not None:
   159          raise GetoptError('option --%s must not have an argument' % opt, opt)
   160      opts.append(('--' + opt, optarg or ''))
   161      return opts, args
   162  
   163  # Return:
   164  #   has_arg?
   165  #   full option name
   166  def long_has_args(opt, longopts):
   167      possibilities = [o for o in longopts if o.startswith(opt)]
   168      if not possibilities:
   169          raise GetoptError('option --%s not recognized' % opt, opt)
   170      # Is there an exact match?
   171      if opt in possibilities:
   172          return False, opt
   173      elif opt + '=' in possibilities:
   174          return True, opt
   175      # No exact match, so better be unique.
   176      if len(possibilities) > 1:
   177          # XXX since possibilities contains all valid continuations, might be
   178          # nice to work them into the error msg
   179          raise GetoptError('option --%s not a unique prefix' % opt, opt)
   180      assert len(possibilities) == 1
   181      unique_match = possibilities[0]
   182      has_arg = unique_match.endswith('=')
   183      if has_arg:
   184          unique_match = unique_match[:-1]
   185      return has_arg, unique_match
   186  
   187  def do_shorts(opts, optstring, shortopts, args):
   188      while optstring != '':
   189          opt, optstring = optstring[0], optstring[1:]
   190          if short_has_arg(opt, shortopts):
   191              if optstring == '':
   192                  if not args:
   193                      raise GetoptError('option -%s requires argument' % opt,
   194                                        opt)
   195                  optstring, args = args[0], args[1:]
   196              optarg, optstring = optstring, ''
   197          else:
   198              optarg = ''
   199          opts.append(('-' + opt, optarg))
   200      return opts, args
   201  
   202  def short_has_arg(opt, shortopts):
   203      for i in range(len(shortopts)):
   204          if opt == shortopts[i] != ':':
   205              return shortopts.startswith(':', i+1)
   206      raise GetoptError('option -%s not recognized' % opt, opt)
   207  
   208  if __name__ == '__main__':
   209      import sys
   210      print getopt(sys.argv[1:], "a:b", ["alpha=", "beta"])