(root)/
Python-3.12.0/
Lib/
getopt.py
       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 Åstrand <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  try:
      38      from gettext import gettext as _
      39  except ImportError:
      40      # Bootstrapping Python: gettext's dependencies not built yet
      41      def _(s): return s
      42  
      43  class ESC[4;38;5;81mGetoptError(ESC[4;38;5;149mException):
      44      opt = ''
      45      msg = ''
      46      def __init__(self, msg, opt=''):
      47          self.msg = msg
      48          self.opt = opt
      49          Exception.__init__(self, msg, opt)
      50  
      51      def __str__(self):
      52          return self.msg
      53  
      54  error = GetoptError # backward compatibility
      55  
      56  def getopt(args, shortopts, longopts = []):
      57      """getopt(args, options[, long_options]) -> opts, args
      58  
      59      Parses command line options and parameter list.  args is the
      60      argument list to be parsed, without the leading reference to the
      61      running program.  Typically, this means "sys.argv[1:]".  shortopts
      62      is the string of option letters that the script wants to
      63      recognize, with options that require an argument followed by a
      64      colon (i.e., the same format that Unix getopt() uses).  If
      65      specified, longopts is a list of strings with the names of the
      66      long options which should be supported.  The leading '--'
      67      characters should not be included in the option name.  Options
      68      which require an argument should be followed by an equal sign
      69      ('=').
      70  
      71      The return value consists of two elements: the first is a list of
      72      (option, value) pairs; the second is the list of program arguments
      73      left after the option list was stripped (this is a trailing slice
      74      of the first argument).  Each option-and-value pair returned has
      75      the option as its first element, prefixed with a hyphen (e.g.,
      76      '-x'), and the option argument as its second element, or an empty
      77      string if the option has no argument.  The options occur in the
      78      list in the same order in which they were found, thus allowing
      79      multiple occurrences.  Long and short options may be mixed.
      80  
      81      """
      82  
      83      opts = []
      84      if isinstance(longopts, str):
      85          longopts = [longopts]
      86      else:
      87          longopts = list(longopts)
      88      while args and args[0].startswith('-') and args[0] != '-':
      89          if args[0] == '--':
      90              args = args[1:]
      91              break
      92          if args[0].startswith('--'):
      93              opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
      94          else:
      95              opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
      96  
      97      return opts, args
      98  
      99  def gnu_getopt(args, shortopts, longopts = []):
     100      """getopt(args, options[, long_options]) -> opts, args
     101  
     102      This function works like getopt(), except that GNU style scanning
     103      mode is used by default. This means that option and non-option
     104      arguments may be intermixed. The getopt() function stops
     105      processing options as soon as a non-option argument is
     106      encountered.
     107  
     108      If the first character of the option string is `+', or if the
     109      environment variable POSIXLY_CORRECT is set, then option
     110      processing stops as soon as a non-option argument is encountered.
     111  
     112      """
     113  
     114      opts = []
     115      prog_args = []
     116      if isinstance(longopts, str):
     117          longopts = [longopts]
     118      else:
     119          longopts = list(longopts)
     120  
     121      # Allow options after non-option arguments?
     122      if shortopts.startswith('+'):
     123          shortopts = shortopts[1:]
     124          all_options_first = True
     125      elif os.environ.get("POSIXLY_CORRECT"):
     126          all_options_first = True
     127      else:
     128          all_options_first = False
     129  
     130      while args:
     131          if args[0] == '--':
     132              prog_args += args[1:]
     133              break
     134  
     135          if args[0][:2] == '--':
     136              opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
     137          elif args[0][:1] == '-' and args[0] != '-':
     138              opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
     139          else:
     140              if all_options_first:
     141                  prog_args += args
     142                  break
     143              else:
     144                  prog_args.append(args[0])
     145                  args = args[1:]
     146  
     147      return opts, prog_args
     148  
     149  def do_longs(opts, opt, longopts, args):
     150      try:
     151          i = opt.index('=')
     152      except ValueError:
     153          optarg = None
     154      else:
     155          opt, optarg = opt[:i], opt[i+1:]
     156  
     157      has_arg, opt = long_has_args(opt, longopts)
     158      if has_arg:
     159          if optarg is None:
     160              if not args:
     161                  raise GetoptError(_('option --%s requires argument') % opt, opt)
     162              optarg, args = args[0], args[1:]
     163      elif optarg is not None:
     164          raise GetoptError(_('option --%s must not have an argument') % opt, opt)
     165      opts.append(('--' + opt, optarg or ''))
     166      return opts, args
     167  
     168  # Return:
     169  #   has_arg?
     170  #   full option name
     171  def long_has_args(opt, longopts):
     172      possibilities = [o for o in longopts if o.startswith(opt)]
     173      if not possibilities:
     174          raise GetoptError(_('option --%s not recognized') % opt, opt)
     175      # Is there an exact match?
     176      if opt in possibilities:
     177          return False, opt
     178      elif opt + '=' in possibilities:
     179          return True, opt
     180      # No exact match, so better be unique.
     181      if len(possibilities) > 1:
     182          # XXX since possibilities contains all valid continuations, might be
     183          # nice to work them into the error msg
     184          raise GetoptError(_('option --%s not a unique prefix') % opt, opt)
     185      assert len(possibilities) == 1
     186      unique_match = possibilities[0]
     187      has_arg = unique_match.endswith('=')
     188      if has_arg:
     189          unique_match = unique_match[:-1]
     190      return has_arg, unique_match
     191  
     192  def do_shorts(opts, optstring, shortopts, args):
     193      while optstring != '':
     194          opt, optstring = optstring[0], optstring[1:]
     195          if short_has_arg(opt, shortopts):
     196              if optstring == '':
     197                  if not args:
     198                      raise GetoptError(_('option -%s requires argument') % opt,
     199                                        opt)
     200                  optstring, args = args[0], args[1:]
     201              optarg, optstring = optstring, ''
     202          else:
     203              optarg = ''
     204          opts.append(('-' + opt, optarg))
     205      return opts, args
     206  
     207  def short_has_arg(opt, shortopts):
     208      for i in range(len(shortopts)):
     209          if opt == shortopts[i] != ':':
     210              return shortopts.startswith(':', i+1)
     211      raise GetoptError(_('option -%s not recognized') % opt, opt)
     212  
     213  if __name__ == '__main__':
     214      import sys
     215      print(getopt(sys.argv[1:], "a:b", ["alpha=", "beta"]))