Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / python / usage.py
1 # -*- test-case-name: twisted.test.test_usage -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5
6 """
7 twisted.python.usage is a module for parsing/handling the
8 command line of your program.
9
10 For information on how to use it, see
11 U{http://twistedmatrix.com/projects/core/documentation/howto/options.html},
12 or doc/core/howto/options.xhtml in your Twisted directory.
13 """
14
15 # System Imports
16 import os
17 import sys
18 import getopt
19 from os import path
20
21 # Sibling Imports
22 from twisted.python import reflect, text, util
23
24
25 class UsageError(Exception):
26     pass
27
28
29 error = UsageError
30
31
32 class CoerceParameter(object):
33     """
34     Utility class that can corce a parameter before storing it.
35     """
36     def __init__(self, options, coerce):
37         """
38         @param options: parent Options object
39         @param coerce: callable used to coerce the value.
40         """
41         self.options = options
42         self.coerce = coerce
43         self.doc = getattr(self.coerce, 'coerceDoc', '')
44
45     def dispatch(self, parameterName, value):
46         """
47         When called in dispatch, do the coerce for C{value} and save the
48         returned value.
49         """
50         if value is None:
51             raise UsageError("Parameter '%s' requires an argument."
52                              % (parameterName,))
53         try:
54             value = self.coerce(value)
55         except ValueError, e:
56             raise UsageError("Parameter type enforcement failed: %s" % (e,))
57
58         self.options.opts[parameterName] = value
59
60
61 class Options(dict):
62     """
63     An option list parser class
64
65     C{optFlags} and C{optParameters} are lists of available parameters
66     which your program can handle. The difference between the two
67     is the 'flags' have an on(1) or off(0) state (off by default)
68     whereas 'parameters' have an assigned value, with an optional
69     default. (Compare '--verbose' and '--verbosity=2')
70
71     optFlags is assigned a list of lists. Each list represents
72     a flag parameter, as so::
73
74     |    optFlags = [['verbose', 'v', 'Makes it tell you what it doing.'],
75     |                ['quiet', 'q', 'Be vewy vewy quiet.']]
76
77     As you can see, the first item is the long option name
78     (prefixed with '--' on the command line), followed by the
79     short option name (prefixed with '-'), and the description.
80     The description is used for the built-in handling of the
81     --help switch, which prints a usage summary.
82
83     C{optParameters} is much the same, except the list also contains
84     a default value::
85
86     | optParameters = [['outfile', 'O', 'outfile.log', 'Description...']]
87
88     A coerce function can also be specified as the last element: it will be
89     called with the argument and should return the value that will be stored
90     for the option. This function can have a C{coerceDoc} attribute which
91     will be appended to the documentation of the option.
92
93     subCommands is a list of 4-tuples of (command name, command shortcut,
94     parser class, documentation).  If the first non-option argument found is
95     one of the given command names, an instance of the given parser class is
96     instantiated and given the remainder of the arguments to parse and
97     self.opts[command] is set to the command name.  For example::
98
99     | subCommands = [
100     |      ['inquisition', 'inquest', InquisitionOptions,
101     |           'Perform an inquisition'],
102     |      ['holyquest', 'quest', HolyQuestOptions,
103     |           'Embark upon a holy quest']
104     |  ]
105
106     In this case, C{"<program> holyquest --horseback --for-grail"} will cause
107     C{HolyQuestOptions} to be instantiated and asked to parse
108     C{['--horseback', '--for-grail']}.  Currently, only the first sub-command
109     is parsed, and all options following it are passed to its parser.  If a
110     subcommand is found, the subCommand attribute is set to its name and the
111     subOptions attribute is set to the Option instance that parses the
112     remaining options. If a subcommand is not given to parseOptions,
113     the subCommand attribute will be None. You can also mark one of
114     the subCommands to be the default.
115
116     | defaultSubCommand = 'holyquest'
117
118     In this case, the subCommand attribute will never be None, and
119     the subOptions attribute will always be set.
120
121     If you want to handle your own options, define a method named
122     C{opt_paramname} that takes C{(self, option)} as arguments. C{option}
123     will be whatever immediately follows the parameter on the
124     command line. Options fully supports the mapping interface, so you
125     can do things like C{'self["option"] = val'} in these methods.
126
127     Shell tab-completion is supported by this class, for zsh only at present.
128     Zsh ships with a stub file ("completion function") which, for Twisted
129     commands, performs tab-completion on-the-fly using the support provided
130     by this class. The stub file lives in our tree at
131     C{twisted/python/twisted-completion.zsh}, and in the Zsh tree at
132     C{Completion/Unix/Command/_twisted}.
133
134     Tab-completion is based upon the contents of the optFlags and optParameters
135     lists. And, optionally, additional metadata may be provided by assigning a
136     special attribute, C{compData}, which should be an instance of
137     C{Completions}. See that class for details of what can and should be
138     included - and see the howto for additional help using these features -
139     including how third-parties may take advantage of tab-completion for their
140     own commands.
141
142     Advanced functionality is covered in the howto documentation,
143     available at
144     U{http://twistedmatrix.com/projects/core/documentation/howto/options.html},
145     or doc/core/howto/options.xhtml in your Twisted directory.
146     """
147
148     subCommand = None
149     defaultSubCommand = None
150     parent = None
151     completionData = None
152     _shellCompFile = sys.stdout # file to use if shell completion is requested
153     def __init__(self):
154         super(Options, self).__init__()
155
156         self.opts = self
157         self.defaults = {}
158
159         # These are strings/lists we will pass to getopt
160         self.longOpt = []
161         self.shortOpt = ''
162         self.docs = {}
163         self.synonyms = {}
164         self._dispatch = {}
165
166
167         collectors = [
168             self._gather_flags,
169             self._gather_parameters,
170             self._gather_handlers,
171             ]
172
173         for c in collectors:
174             (longOpt, shortOpt, docs, settings, synonyms, dispatch) = c()
175             self.longOpt.extend(longOpt)
176             self.shortOpt = self.shortOpt + shortOpt
177             self.docs.update(docs)
178
179             self.opts.update(settings)
180             self.defaults.update(settings)
181
182             self.synonyms.update(synonyms)
183             self._dispatch.update(dispatch)
184
185     def __hash__(self):
186         """
187         Define a custom hash function so that Options instances can be used
188         as dictionary keys.  This is an internal feature used to implement
189         the parser.  Do not rely on it in application code.
190         """
191         return int(id(self) % sys.maxint)
192
193     def opt_help(self):
194         """
195         Display this help and exit.
196         """
197         print self.__str__()
198         sys.exit(0)
199
200     def opt_version(self):
201         """
202         Display Twisted version and exit.
203         """
204         from twisted import copyright
205         print "Twisted version:", copyright.version
206         sys.exit(0)
207
208     #opt_h = opt_help # this conflicted with existing 'host' options.
209
210     def parseOptions(self, options=None):
211         """
212         The guts of the command-line parser.
213         """
214
215         if options is None:
216             options = sys.argv[1:]
217
218         # we really do need to place the shell completion check here, because
219         # if we used an opt_shell_completion method then it would be possible
220         # for other opt_* methods to be run first, and they could possibly
221         # raise validation errors which would result in error output on the
222         # terminal of the user performing shell completion. Validation errors
223         # would occur quite frequently, in fact, because users often initiate
224         # tab-completion while they are editing an unfinished command-line.
225         if len(options) > 1 and options[-2] == "--_shell-completion":
226             from twisted.python import _shellcomp
227             cmdName = path.basename(sys.argv[0])
228             _shellcomp.shellComplete(self, cmdName, options,
229                                      self._shellCompFile)
230             sys.exit(0)
231
232         try:
233             opts, args = getopt.getopt(options,
234                                        self.shortOpt, self.longOpt)
235         except getopt.error, e:
236             raise UsageError(str(e))
237
238         for opt, arg in opts:
239             if opt[1] == '-':
240                 opt = opt[2:]
241             else:
242                 opt = opt[1:]
243
244             optMangled = opt
245             if optMangled not in self.synonyms:
246                 optMangled = opt.replace("-", "_")
247                 if optMangled not in self.synonyms:
248                     raise UsageError("No such option '%s'" % (opt,))
249
250             optMangled = self.synonyms[optMangled]
251             if isinstance(self._dispatch[optMangled], CoerceParameter):
252                 self._dispatch[optMangled].dispatch(optMangled, arg)
253             else:
254                 self._dispatch[optMangled](optMangled, arg)
255
256         if (getattr(self, 'subCommands', None)
257             and (args or self.defaultSubCommand is not None)):
258             if not args:
259                 args = [self.defaultSubCommand]
260             sub, rest = args[0], args[1:]
261             for (cmd, short, parser, doc) in self.subCommands:
262                 if sub == cmd or sub == short:
263                     self.subCommand = cmd
264                     self.subOptions = parser()
265                     self.subOptions.parent = self
266                     self.subOptions.parseOptions(rest)
267                     break
268             else:
269                 raise UsageError("Unknown command: %s" % sub)
270         else:
271             try:
272                 self.parseArgs(*args)
273             except TypeError:
274                 raise UsageError("Wrong number of arguments.")
275
276         self.postOptions()
277
278     def postOptions(self):
279         """
280         I am called after the options are parsed.
281
282         Override this method in your subclass to do something after
283         the options have been parsed and assigned, like validate that
284         all options are sane.
285         """
286
287     def parseArgs(self):
288         """
289         I am called with any leftover arguments which were not options.
290
291         Override me to do something with the remaining arguments on
292         the command line, those which were not flags or options. e.g.
293         interpret them as a list of files to operate on.
294
295         Note that if there more arguments on the command line
296         than this method accepts, parseArgs will blow up with
297         a getopt.error.  This means if you don't override me,
298         parseArgs will blow up if I am passed any arguments at
299         all!
300         """
301
302     def _generic_flag(self, flagName, value=None):
303         if value not in ('', None):
304             raise UsageError("Flag '%s' takes no argument."
305                              " Not even \"%s\"." % (flagName, value))
306
307         self.opts[flagName] = 1
308
309     def _gather_flags(self):
310         """
311         Gather up boolean (flag) options.
312         """
313
314         longOpt, shortOpt = [], ''
315         docs, settings, synonyms, dispatch = {}, {}, {}, {}
316
317         flags = []
318         reflect.accumulateClassList(self.__class__, 'optFlags', flags)
319
320         for flag in flags:
321             long, short, doc = util.padTo(3, flag)
322             if not long:
323                 raise ValueError("A flag cannot be without a name.")
324
325             docs[long] = doc
326             settings[long] = 0
327             if short:
328                 shortOpt = shortOpt + short
329                 synonyms[short] = long
330             longOpt.append(long)
331             synonyms[long] = long
332             dispatch[long] = self._generic_flag
333
334         return longOpt, shortOpt, docs, settings, synonyms, dispatch
335
336     def _gather_parameters(self):
337         """
338         Gather options which take a value.
339         """
340         longOpt, shortOpt = [], ''
341         docs, settings, synonyms, dispatch = {}, {}, {}, {}
342
343         parameters = []
344
345         reflect.accumulateClassList(self.__class__, 'optParameters',
346                                     parameters)
347
348         synonyms = {}
349
350         for parameter in parameters:
351             long, short, default, doc, paramType = util.padTo(5, parameter)
352             if not long:
353                 raise ValueError("A parameter cannot be without a name.")
354
355             docs[long] = doc
356             settings[long] = default
357             if short:
358                 shortOpt = shortOpt + short + ':'
359                 synonyms[short] = long
360             longOpt.append(long + '=')
361             synonyms[long] = long
362             if paramType is not None:
363                 dispatch[long] = CoerceParameter(self, paramType)
364             else:
365                 dispatch[long] = CoerceParameter(self, str)
366
367         return longOpt, shortOpt, docs, settings, synonyms, dispatch
368
369
370     def _gather_handlers(self):
371         """
372         Gather up options with their own handler methods.
373
374         This returns a tuple of many values.  Amongst those values is a
375         synonyms dictionary, mapping all of the possible aliases (C{str})
376         for an option to the longest spelling of that option's name
377         C({str}).
378
379         Another element is a dispatch dictionary, mapping each user-facing
380         option name (with - substituted for _) to a callable to handle that
381         option.
382         """
383
384         longOpt, shortOpt = [], ''
385         docs, settings, synonyms, dispatch = {}, {}, {}, {}
386
387         dct = {}
388         reflect.addMethodNamesToDict(self.__class__, dct, "opt_")
389
390         for name in dct.keys():
391             method = getattr(self, 'opt_'+name)
392
393             takesArg = not flagFunction(method, name)
394
395             prettyName = name.replace('_', '-')
396             doc = getattr(method, '__doc__', None)
397             if doc:
398                 ## Only use the first line.
399                 #docs[name] = doc.split('\n')[0]
400                 docs[prettyName] = doc
401             else:
402                 docs[prettyName] = self.docs.get(prettyName)
403
404             synonyms[prettyName] = prettyName
405
406             # A little slight-of-hand here makes dispatching much easier
407             # in parseOptions, as it makes all option-methods have the
408             # same signature.
409             if takesArg:
410                 fn = lambda name, value, m=method: m(value)
411             else:
412                 # XXX: This won't raise a TypeError if it's called
413                 # with a value when it shouldn't be.
414                 fn = lambda name, value=None, m=method: m()
415
416             dispatch[prettyName] = fn
417
418             if len(name) == 1:
419                 shortOpt = shortOpt + name
420                 if takesArg:
421                     shortOpt = shortOpt + ':'
422             else:
423                 if takesArg:
424                     prettyName = prettyName + '='
425                 longOpt.append(prettyName)
426
427         reverse_dct = {}
428         # Map synonyms
429         for name in dct.keys():
430             method = getattr(self, 'opt_' + name)
431             if method not in reverse_dct:
432                 reverse_dct[method] = []
433             reverse_dct[method].append(name.replace('_', '-'))
434
435         cmpLength = lambda a, b: cmp(len(a), len(b))
436
437         for method, names in reverse_dct.items():
438             if len(names) < 2:
439                 continue
440             names_ = names[:]
441             names_.sort(cmpLength)
442             longest = names_.pop()
443             for name in names_:
444                 synonyms[name] = longest
445
446         return longOpt, shortOpt, docs, settings, synonyms, dispatch
447
448
449     def __str__(self):
450         return self.getSynopsis() + '\n' + self.getUsage(width=None)
451
452     def getSynopsis(self):
453         """
454         Returns a string containing a description of these options and how to
455         pass them to the executed file.
456         """
457
458         default = "%s%s" % (path.basename(sys.argv[0]),
459                             (self.longOpt and " [options]") or '')
460         if self.parent is None:
461             default = "Usage: %s%s" % (path.basename(sys.argv[0]),
462                                        (self.longOpt and " [options]") or '')
463         else:
464             default = '%s' % ((self.longOpt and "[options]") or '')
465         synopsis = getattr(self, "synopsis", default)
466
467         synopsis = synopsis.rstrip()
468
469         if self.parent is not None:
470             synopsis = ' '.join((self.parent.getSynopsis(),
471                                  self.parent.subCommand, synopsis))
472
473         return synopsis
474
475     def getUsage(self, width=None):
476         # If subOptions exists by now, then there was probably an error while
477         # parsing its options.
478         if hasattr(self, 'subOptions'):
479             return self.subOptions.getUsage(width=width)
480
481         if not width:
482             width = int(os.environ.get('COLUMNS', '80'))
483
484         if hasattr(self, 'subCommands'):
485             cmdDicts = []
486             for (cmd, short, parser, desc) in self.subCommands:
487                 cmdDicts.append(
488                     {'long': cmd,
489                      'short': short,
490                      'doc': desc,
491                      'optType': 'command',
492                      'default': None
493                     })
494             chunks = docMakeChunks(cmdDicts, width)
495             commands = 'Commands:\n' + ''.join(chunks)
496         else:
497             commands = ''
498
499         longToShort = {}
500         for key, value in self.synonyms.items():
501             longname = value
502             if (key != longname) and (len(key) == 1):
503                 longToShort[longname] = key
504             else:
505                 if longname not in longToShort:
506                     longToShort[longname] = None
507                 else:
508                     pass
509
510         optDicts = []
511         for opt in self.longOpt:
512             if opt[-1] == '=':
513                 optType = 'parameter'
514                 opt = opt[:-1]
515             else:
516                 optType = 'flag'
517
518             optDicts.append(
519                 {'long': opt,
520                  'short': longToShort[opt],
521                  'doc': self.docs[opt],
522                  'optType': optType,
523                  'default': self.defaults.get(opt, None),
524                  'dispatch': self._dispatch.get(opt, None)
525                  })
526
527         if not (getattr(self, "longdesc", None) is None):
528             longdesc = self.longdesc
529         else:
530             import __main__
531             if getattr(__main__, '__doc__', None):
532                 longdesc = __main__.__doc__
533             else:
534                 longdesc = ''
535
536         if longdesc:
537             longdesc = ('\n' +
538                         '\n'.join(text.wordWrap(longdesc, width)).strip()
539                         + '\n')
540
541         if optDicts:
542             chunks = docMakeChunks(optDicts, width)
543             s = "Options:\n%s" % (''.join(chunks))
544         else:
545             s = "Options: None\n"
546
547         return s + longdesc + commands
548
549     #def __repr__(self):
550     #    XXX: It'd be cool if we could return a succinct representation
551     #        of which flags and options are set here.
552
553
554 _ZSH = 'zsh'
555 _BASH = 'bash'
556
557 class Completer(object):
558     """
559     A completion "action" - provides completion possibilities for a particular
560     command-line option. For example we might provide the user a fixed list of
561     choices, or files/dirs according to a glob.
562
563     This class produces no completion matches itself - see the various
564     subclasses for specific completion functionality.
565     """
566     _descr = None
567     def __init__(self, descr=None, repeat=False):
568         """
569         @type descr: C{str}
570         @param descr: An optional descriptive string displayed above matches.
571
572         @type repeat: C{bool}
573         @param repeat: A flag, defaulting to False, indicating whether this
574             C{Completer} should repeat - that is, be used to complete more
575             than one command-line word. This may ONLY be set to True for
576             actions in the C{extraActions} keyword argument to C{Completions}.
577             And ONLY if it is the LAST (or only) action in the C{extraActions}
578             list.
579         """
580         if descr is not None:
581             self._descr = descr
582         self._repeat = repeat
583
584
585     def _getRepeatFlag(self):
586         if self._repeat:
587             return "*"
588         else:
589             return ""
590     _repeatFlag = property(_getRepeatFlag)
591
592
593     def _description(self, optName):
594         if self._descr is not None:
595             return self._descr
596         else:
597             return optName
598
599
600     def _shellCode(self, optName, shellType):
601         """
602         Fetch a fragment of shell code representing this action which is
603         suitable for use by the completion system in _shellcomp.py
604
605         @type optName: C{str}
606         @param optName: The long name of the option this action is being
607             used for.
608
609         @type shellType: C{str}
610         @param shellType: One of the supported shell constants e.g.
611             C{twisted.python.usage._ZSH}
612         """
613         if shellType == _ZSH:
614             return "%s:%s:" % (self._repeatFlag,
615                                self._description(optName))
616         raise NotImplementedError("Unknown shellType %r" % (shellType,))
617
618
619
620 class CompleteFiles(Completer):
621     """
622     Completes file names based on a glob pattern
623     """
624     def __init__(self, globPattern='*', **kw):
625         Completer.__init__(self, **kw)
626         self._globPattern = globPattern
627
628
629     def _description(self, optName):
630         if self._descr is not None:
631             return "%s (%s)" % (self._descr, self._globPattern)
632         else:
633             return "%s (%s)" % (optName, self._globPattern)
634
635
636     def _shellCode(self, optName, shellType):
637         if shellType == _ZSH:
638             return "%s:%s:_files -g \"%s\"" % (self._repeatFlag,
639                                                self._description(optName),
640                                                self._globPattern,)
641         raise NotImplementedError("Unknown shellType %r" % (shellType,))
642
643
644
645 class CompleteDirs(Completer):
646     """
647     Completes directory names
648     """
649     def _shellCode(self, optName, shellType):
650         if shellType == _ZSH:
651             return "%s:%s:_directories" % (self._repeatFlag,
652                                            self._description(optName))
653         raise NotImplementedError("Unknown shellType %r" % (shellType,))
654
655
656
657 class CompleteList(Completer):
658     """
659     Completes based on a fixed list of words
660     """
661     def __init__(self, items, **kw):
662         Completer.__init__(self, **kw)
663         self._items = items
664
665     def _shellCode(self, optName, shellType):
666         if shellType == _ZSH:
667             return "%s:%s:(%s)" % (self._repeatFlag,
668                                    self._description(optName),
669                                    " ".join(self._items,))
670         raise NotImplementedError("Unknown shellType %r" % (shellType,))
671
672
673
674 class CompleteMultiList(Completer):
675     """
676     Completes multiple comma-separated items based on a fixed list of words
677     """
678     def __init__(self, items, **kw):
679         Completer.__init__(self, **kw)
680         self._items = items
681
682     def _shellCode(self, optName, shellType):
683         if shellType == _ZSH:
684             return "%s:%s:_values -s , '%s' %s" % (self._repeatFlag,
685                                                    self._description(optName),
686                                                    self._description(optName),
687                                                    " ".join(self._items))
688         raise NotImplementedError("Unknown shellType %r" % (shellType,))
689
690
691
692 class CompleteUsernames(Completer):
693     """
694     Complete usernames
695     """
696     def _shellCode(self, optName, shellType):
697         if shellType == _ZSH:
698             return "%s:%s:_users" % (self._repeatFlag,
699                                      self._description(optName))
700         raise NotImplementedError("Unknown shellType %r" % (shellType,))
701
702
703
704 class CompleteGroups(Completer):
705     """
706     Complete system group names
707     """
708     _descr = 'group'
709     def _shellCode(self, optName, shellType):
710         if shellType == _ZSH:
711             return "%s:%s:_groups" % (self._repeatFlag,
712                                       self._description(optName))
713         raise NotImplementedError("Unknown shellType %r" % (shellType,))
714
715
716
717 class CompleteHostnames(Completer):
718     """
719     Complete hostnames
720     """
721     def _shellCode(self, optName, shellType):
722         if shellType == _ZSH:
723             return "%s:%s:_hosts" % (self._repeatFlag,
724                                      self._description(optName))
725         raise NotImplementedError("Unknown shellType %r" % (shellType,))
726
727
728
729 class CompleteUserAtHost(Completer):
730     """
731     A completion action which produces matches in any of these forms::
732         <username>
733         <hostname>
734         <username>@<hostname>
735     """
736     _descr = 'host | user@host'
737     def _shellCode(self, optName, shellType):
738         if shellType == _ZSH:
739             # Yes this looks insane but it does work. For bonus points
740             # add code to grep 'Hostname' lines from ~/.ssh/config
741             return ('%s:%s:{_ssh;if compset -P "*@"; '
742                     'then _wanted hosts expl "remote host name" _ssh_hosts '
743                     '&& ret=0 elif compset -S "@*"; then _wanted users '
744                     'expl "login name" _ssh_users -S "" && ret=0 '
745                     'else if (( $+opt_args[-l] )); then tmp=() '
746                     'else tmp=( "users:login name:_ssh_users -qS@" ) fi; '
747                     '_alternative "hosts:remote host name:_ssh_hosts" "$tmp[@]"'
748                     ' && ret=0 fi}' % (self._repeatFlag,
749                                        self._description(optName)))
750         raise NotImplementedError("Unknown shellType %r" % (shellType,))
751
752
753
754 class CompleteNetInterfaces(Completer):
755     """
756     Complete network interface names
757     """
758     def _shellCode(self, optName, shellType):
759         if shellType == _ZSH:
760             return "%s:%s:_net_interfaces" % (self._repeatFlag,
761                                               self._description(optName))
762         raise NotImplementedError("Unknown shellType %r" % (shellType,))
763
764
765
766 class Completions(object):
767     """
768     Extra metadata for the shell tab-completion system.
769
770     @type descriptions: C{dict}
771     @ivar descriptions: ex. C{{"foo" : "use this description for foo instead"}}
772         A dict mapping long option names to alternate descriptions.  When this
773         variable is defined, the descriptions contained here will override
774         those descriptions provided in the optFlags and optParameters
775         variables.
776
777     @type multiUse: C{list}
778     @ivar multiUse: ex. C{ ["foo", "bar"] }
779         An iterable containing those long option names which may appear on the
780         command line more than once. By default, options will only be completed
781         one time.
782
783     @type mutuallyExclusive: C{list} of C{tuple}
784     @ivar mutuallyExclusive: ex. C{ [("foo", "bar"), ("bar", "baz")] }
785         A sequence of sequences, with each sub-sequence containing those long
786         option names that are mutually exclusive. That is, those options that
787         cannot appear on the command line together.
788
789     @type optActions: C{dict}
790     @ivar optActions: A dict mapping long option names to shell "actions".
791         These actions define what may be completed as the argument to the
792         given option. By default, all files/dirs will be completed if no
793         action is given. For example::
794
795             {"foo"    : CompleteFiles("*.py", descr="python files"),
796              "bar"    : CompleteList(["one", "two", "three"]),
797              "colors" : CompleteMultiList(["red", "green", "blue"])}
798
799         Callables may instead be given for the values in this dict. The
800         callable should accept no arguments, and return a C{Completer}
801         instance used as the action in the same way as the literal actions in
802         the example above.
803
804         As you can see in the example above. The "foo" option will have files
805         that end in .py completed when the user presses Tab. The "bar"
806         option will have either of the strings "one", "two", or "three"
807         completed when the user presses Tab.
808
809         "colors" will allow multiple arguments to be completed, seperated by
810         commas. The possible arguments are red, green, and blue. Examples::
811
812             my_command --foo some-file.foo --colors=red,green
813             my_command --colors=green
814             my_command --colors=green,blue
815
816         Descriptions for the actions may be given with the optional C{descr}
817         keyword argument. This is separate from the description of the option
818         itself.
819
820         Normally Zsh does not show these descriptions unless you have
821         "verbose" completion turned on. Turn on verbosity with this in your
822         ~/.zshrc::
823
824             zstyle ':completion:*' verbose yes
825             zstyle ':completion:*:descriptions' format '%B%d%b'
826
827     @type extraActions: C{list}
828     @ivar extraActions: Extra arguments are those arguments typically
829         appearing at the end of the command-line, which are not associated
830         with any particular named option. That is, the arguments that are
831         given to the parseArgs() method of your usage.Options subclass. For
832         example::
833             [CompleteFiles(descr="file to read from"),
834              Completer(descr="book title")]
835
836         In the example above, the 1st non-option argument will be described as
837         "file to read from" and all file/dir names will be completed (*). The
838         2nd non-option argument will be described as "book title", but no
839         actual completion matches will be produced.
840
841         See the various C{Completer} subclasses for other types of things which
842         may be tab-completed (users, groups, network interfaces, etc).
843
844         Also note the C{repeat=True} flag which may be passed to any of the
845         C{Completer} classes. This is set to allow the C{Completer} instance
846         to be re-used for subsequent command-line words. See the C{Completer}
847         docstring for details.
848     """
849     def __init__(self, descriptions={}, multiUse=[],
850                  mutuallyExclusive=[], optActions={}, extraActions=[]):
851         self.descriptions = descriptions
852         self.multiUse = multiUse
853         self.mutuallyExclusive = mutuallyExclusive
854         self.optActions = optActions
855         self.extraActions = extraActions
856
857
858
859 def docMakeChunks(optList, width=80):
860     """
861     Makes doc chunks for option declarations.
862
863     Takes a list of dictionaries, each of which may have one or more
864     of the keys 'long', 'short', 'doc', 'default', 'optType'.
865
866     Returns a list of strings.
867     The strings may be multiple lines,
868     all of them end with a newline.
869     """
870
871     # XXX: sanity check to make sure we have a sane combination of keys.
872
873     maxOptLen = 0
874     for opt in optList:
875         optLen = len(opt.get('long', ''))
876         if optLen:
877             if opt.get('optType', None) == "parameter":
878                 # these take up an extra character
879                 optLen = optLen + 1
880             maxOptLen = max(optLen, maxOptLen)
881
882     colWidth1 = maxOptLen + len("  -s, --  ")
883     colWidth2 = width - colWidth1
884     # XXX - impose some sane minimum limit.
885     # Then if we don't have enough room for the option and the doc
886     # to share one line, they can take turns on alternating lines.
887
888     colFiller1 = " " * colWidth1
889
890     optChunks = []
891     seen = {}
892     for opt in optList:
893         if opt.get('short', None) in seen or opt.get('long', None) in seen:
894             continue
895         for x in opt.get('short', None), opt.get('long', None):
896             if x is not None:
897                 seen[x] = 1
898
899         optLines = []
900         comma = " "
901         if opt.get('short', None):
902             short = "-%c" % (opt['short'],)
903         else:
904             short = ''
905
906         if opt.get('long', None):
907             long = opt['long']
908             if opt.get("optType", None) == "parameter":
909                 long = long + '='
910
911             long = "%-*s" % (maxOptLen, long)
912             if short:
913                 comma = ","
914         else:
915             long = " " * (maxOptLen + len('--'))
916
917         if opt.get('optType', None) == 'command':
918             column1 = '    %s      ' % long
919         else:
920             column1 = "  %2s%c --%s  " % (short, comma, long)
921
922         if opt.get('doc', ''):
923             doc = opt['doc'].strip()
924         else:
925             doc = ''
926
927         if (opt.get("optType", None) == "parameter") \
928            and not (opt.get('default', None) is None):
929             doc = "%s [default: %s]" % (doc, opt['default'])
930
931         if (opt.get("optType", None) == "parameter") \
932            and opt.get('dispatch', None) is not None:
933             d = opt['dispatch']
934             if isinstance(d, CoerceParameter) and d.doc:
935                 doc = "%s. %s" % (doc, d.doc)
936
937         if doc:
938             column2_l = text.wordWrap(doc, colWidth2)
939         else:
940             column2_l = ['']
941
942         optLines.append("%s%s\n" % (column1, column2_l.pop(0)))
943
944         for line in column2_l:
945             optLines.append("%s%s\n" % (colFiller1, line))
946
947         optChunks.append(''.join(optLines))
948
949     return optChunks
950
951
952 def flagFunction(method, name=None):
953     reqArgs = method.im_func.func_code.co_argcount
954     if reqArgs > 2:
955         raise UsageError('Invalid Option function for %s' %
956                          (name or method.func_name))
957     if reqArgs == 2:
958         # argName = method.im_func.func_code.co_varnames[1]
959         return 0
960     return 1
961
962
963 def portCoerce(value):
964     """
965     Coerce a string value to an int port number, and checks the validity.
966     """
967     value = int(value)
968     if value < 0 or value > 65535:
969         raise ValueError("Port number not in range: %s" % (value,))
970     return value
971 portCoerce.coerceDoc = "Must be an int between 0 and 65535."
972
973