1 # -*- test-case-name: twisted.test.test_usage -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
7 twisted.python.usage is a module for parsing/handling the
8 command line of your program.
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.
22 from twisted.python import reflect, text, util
25 class UsageError(Exception):
32 class CoerceParameter(object):
34 Utility class that can corce a parameter before storing it.
36 def __init__(self, options, coerce):
38 @param options: parent Options object
39 @param coerce: callable used to coerce the value.
41 self.options = options
43 self.doc = getattr(self.coerce, 'coerceDoc', '')
45 def dispatch(self, parameterName, value):
47 When called in dispatch, do the coerce for C{value} and save the
51 raise UsageError("Parameter '%s' requires an argument."
54 value = self.coerce(value)
56 raise UsageError("Parameter type enforcement failed: %s" % (e,))
58 self.options.opts[parameterName] = value
63 An option list parser class
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')
71 optFlags is assigned a list of lists. Each list represents
72 a flag parameter, as so::
74 | optFlags = [['verbose', 'v', 'Makes it tell you what it doing.'],
75 | ['quiet', 'q', 'Be vewy vewy quiet.']]
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.
83 C{optParameters} is much the same, except the list also contains
86 | optParameters = [['outfile', 'O', 'outfile.log', 'Description...']]
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.
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::
100 | ['inquisition', 'inquest', InquisitionOptions,
101 | 'Perform an inquisition'],
102 | ['holyquest', 'quest', HolyQuestOptions,
103 | 'Embark upon a holy quest']
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.
116 | defaultSubCommand = 'holyquest'
118 In this case, the subCommand attribute will never be None, and
119 the subOptions attribute will always be set.
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.
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}.
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
142 Advanced functionality is covered in the howto documentation,
144 U{http://twistedmatrix.com/projects/core/documentation/howto/options.html},
145 or doc/core/howto/options.xhtml in your Twisted directory.
149 defaultSubCommand = None
151 completionData = None
152 _shellCompFile = sys.stdout # file to use if shell completion is requested
154 super(Options, self).__init__()
159 # These are strings/lists we will pass to getopt
169 self._gather_parameters,
170 self._gather_handlers,
174 (longOpt, shortOpt, docs, settings, synonyms, dispatch) = c()
175 self.longOpt.extend(longOpt)
176 self.shortOpt = self.shortOpt + shortOpt
177 self.docs.update(docs)
179 self.opts.update(settings)
180 self.defaults.update(settings)
182 self.synonyms.update(synonyms)
183 self._dispatch.update(dispatch)
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.
191 return int(id(self) % sys.maxint)
195 Display this help and exit.
200 def opt_version(self):
202 Display Twisted version and exit.
204 from twisted import copyright
205 print "Twisted version:", copyright.version
208 #opt_h = opt_help # this conflicted with existing 'host' options.
210 def parseOptions(self, options=None):
212 The guts of the command-line parser.
216 options = sys.argv[1:]
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,
233 opts, args = getopt.getopt(options,
234 self.shortOpt, self.longOpt)
235 except getopt.error, e:
236 raise UsageError(str(e))
238 for opt, arg in opts:
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,))
250 optMangled = self.synonyms[optMangled]
251 if isinstance(self._dispatch[optMangled], CoerceParameter):
252 self._dispatch[optMangled].dispatch(optMangled, arg)
254 self._dispatch[optMangled](optMangled, arg)
256 if (getattr(self, 'subCommands', None)
257 and (args or self.defaultSubCommand is not None)):
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)
269 raise UsageError("Unknown command: %s" % sub)
272 self.parseArgs(*args)
274 raise UsageError("Wrong number of arguments.")
278 def postOptions(self):
280 I am called after the options are parsed.
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.
289 I am called with any leftover arguments which were not options.
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.
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
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))
307 self.opts[flagName] = 1
309 def _gather_flags(self):
311 Gather up boolean (flag) options.
314 longOpt, shortOpt = [], ''
315 docs, settings, synonyms, dispatch = {}, {}, {}, {}
318 reflect.accumulateClassList(self.__class__, 'optFlags', flags)
321 long, short, doc = util.padTo(3, flag)
323 raise ValueError("A flag cannot be without a name.")
328 shortOpt = shortOpt + short
329 synonyms[short] = long
331 synonyms[long] = long
332 dispatch[long] = self._generic_flag
334 return longOpt, shortOpt, docs, settings, synonyms, dispatch
336 def _gather_parameters(self):
338 Gather options which take a value.
340 longOpt, shortOpt = [], ''
341 docs, settings, synonyms, dispatch = {}, {}, {}, {}
345 reflect.accumulateClassList(self.__class__, 'optParameters',
350 for parameter in parameters:
351 long, short, default, doc, paramType = util.padTo(5, parameter)
353 raise ValueError("A parameter cannot be without a name.")
356 settings[long] = default
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)
365 dispatch[long] = CoerceParameter(self, str)
367 return longOpt, shortOpt, docs, settings, synonyms, dispatch
370 def _gather_handlers(self):
372 Gather up options with their own handler methods.
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
379 Another element is a dispatch dictionary, mapping each user-facing
380 option name (with - substituted for _) to a callable to handle that
384 longOpt, shortOpt = [], ''
385 docs, settings, synonyms, dispatch = {}, {}, {}, {}
388 reflect.addMethodNamesToDict(self.__class__, dct, "opt_")
390 for name in dct.keys():
391 method = getattr(self, 'opt_'+name)
393 takesArg = not flagFunction(method, name)
395 prettyName = name.replace('_', '-')
396 doc = getattr(method, '__doc__', None)
398 ## Only use the first line.
399 #docs[name] = doc.split('\n')[0]
400 docs[prettyName] = doc
402 docs[prettyName] = self.docs.get(prettyName)
404 synonyms[prettyName] = prettyName
406 # A little slight-of-hand here makes dispatching much easier
407 # in parseOptions, as it makes all option-methods have the
410 fn = lambda name, value, m=method: m(value)
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()
416 dispatch[prettyName] = fn
419 shortOpt = shortOpt + name
421 shortOpt = shortOpt + ':'
424 prettyName = prettyName + '='
425 longOpt.append(prettyName)
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('_', '-'))
435 cmpLength = lambda a, b: cmp(len(a), len(b))
437 for method, names in reverse_dct.items():
441 names_.sort(cmpLength)
442 longest = names_.pop()
444 synonyms[name] = longest
446 return longOpt, shortOpt, docs, settings, synonyms, dispatch
450 return self.getSynopsis() + '\n' + self.getUsage(width=None)
452 def getSynopsis(self):
454 Returns a string containing a description of these options and how to
455 pass them to the executed file.
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 '')
464 default = '%s' % ((self.longOpt and "[options]") or '')
465 synopsis = getattr(self, "synopsis", default)
467 synopsis = synopsis.rstrip()
469 if self.parent is not None:
470 synopsis = ' '.join((self.parent.getSynopsis(),
471 self.parent.subCommand, synopsis))
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)
482 width = int(os.environ.get('COLUMNS', '80'))
484 if hasattr(self, 'subCommands'):
486 for (cmd, short, parser, desc) in self.subCommands:
491 'optType': 'command',
494 chunks = docMakeChunks(cmdDicts, width)
495 commands = 'Commands:\n' + ''.join(chunks)
500 for key, value in self.synonyms.items():
502 if (key != longname) and (len(key) == 1):
503 longToShort[longname] = key
505 if longname not in longToShort:
506 longToShort[longname] = None
511 for opt in self.longOpt:
513 optType = 'parameter'
520 'short': longToShort[opt],
521 'doc': self.docs[opt],
523 'default': self.defaults.get(opt, None),
524 'dispatch': self._dispatch.get(opt, None)
527 if not (getattr(self, "longdesc", None) is None):
528 longdesc = self.longdesc
531 if getattr(__main__, '__doc__', None):
532 longdesc = __main__.__doc__
538 '\n'.join(text.wordWrap(longdesc, width)).strip()
542 chunks = docMakeChunks(optDicts, width)
543 s = "Options:\n%s" % (''.join(chunks))
545 s = "Options: None\n"
547 return s + longdesc + commands
550 # XXX: It'd be cool if we could return a succinct representation
551 # of which flags and options are set here.
557 class Completer(object):
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.
563 This class produces no completion matches itself - see the various
564 subclasses for specific completion functionality.
567 def __init__(self, descr=None, repeat=False):
570 @param descr: An optional descriptive string displayed above matches.
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}
580 if descr is not None:
582 self._repeat = repeat
585 def _getRepeatFlag(self):
590 _repeatFlag = property(_getRepeatFlag)
593 def _description(self, optName):
594 if self._descr is not None:
600 def _shellCode(self, optName, shellType):
602 Fetch a fragment of shell code representing this action which is
603 suitable for use by the completion system in _shellcomp.py
605 @type optName: C{str}
606 @param optName: The long name of the option this action is being
609 @type shellType: C{str}
610 @param shellType: One of the supported shell constants e.g.
611 C{twisted.python.usage._ZSH}
613 if shellType == _ZSH:
614 return "%s:%s:" % (self._repeatFlag,
615 self._description(optName))
616 raise NotImplementedError("Unknown shellType %r" % (shellType,))
620 class CompleteFiles(Completer):
622 Completes file names based on a glob pattern
624 def __init__(self, globPattern='*', **kw):
625 Completer.__init__(self, **kw)
626 self._globPattern = globPattern
629 def _description(self, optName):
630 if self._descr is not None:
631 return "%s (%s)" % (self._descr, self._globPattern)
633 return "%s (%s)" % (optName, self._globPattern)
636 def _shellCode(self, optName, shellType):
637 if shellType == _ZSH:
638 return "%s:%s:_files -g \"%s\"" % (self._repeatFlag,
639 self._description(optName),
641 raise NotImplementedError("Unknown shellType %r" % (shellType,))
645 class CompleteDirs(Completer):
647 Completes directory names
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,))
657 class CompleteList(Completer):
659 Completes based on a fixed list of words
661 def __init__(self, items, **kw):
662 Completer.__init__(self, **kw)
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,))
674 class CompleteMultiList(Completer):
676 Completes multiple comma-separated items based on a fixed list of words
678 def __init__(self, items, **kw):
679 Completer.__init__(self, **kw)
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,))
692 class CompleteUsernames(Completer):
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,))
704 class CompleteGroups(Completer):
706 Complete system group names
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,))
717 class CompleteHostnames(Completer):
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,))
729 class CompleteUserAtHost(Completer):
731 A completion action which produces matches in any of these forms::
734 <username>@<hostname>
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,))
754 class CompleteNetInterfaces(Completer):
756 Complete network interface names
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,))
766 class Completions(object):
768 Extra metadata for the shell tab-completion system.
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
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
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.
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::
795 {"foo" : CompleteFiles("*.py", descr="python files"),
796 "bar" : CompleteList(["one", "two", "three"]),
797 "colors" : CompleteMultiList(["red", "green", "blue"])}
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
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.
809 "colors" will allow multiple arguments to be completed, seperated by
810 commas. The possible arguments are red, green, and blue. Examples::
812 my_command --foo some-file.foo --colors=red,green
813 my_command --colors=green
814 my_command --colors=green,blue
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
820 Normally Zsh does not show these descriptions unless you have
821 "verbose" completion turned on. Turn on verbosity with this in your
824 zstyle ':completion:*' verbose yes
825 zstyle ':completion:*:descriptions' format '%B%d%b'
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
833 [CompleteFiles(descr="file to read from"),
834 Completer(descr="book title")]
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.
841 See the various C{Completer} subclasses for other types of things which
842 may be tab-completed (users, groups, network interfaces, etc).
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.
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
859 def docMakeChunks(optList, width=80):
861 Makes doc chunks for option declarations.
863 Takes a list of dictionaries, each of which may have one or more
864 of the keys 'long', 'short', 'doc', 'default', 'optType'.
866 Returns a list of strings.
867 The strings may be multiple lines,
868 all of them end with a newline.
871 # XXX: sanity check to make sure we have a sane combination of keys.
875 optLen = len(opt.get('long', ''))
877 if opt.get('optType', None) == "parameter":
878 # these take up an extra character
880 maxOptLen = max(optLen, maxOptLen)
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.
888 colFiller1 = " " * colWidth1
893 if opt.get('short', None) in seen or opt.get('long', None) in seen:
895 for x in opt.get('short', None), opt.get('long', None):
901 if opt.get('short', None):
902 short = "-%c" % (opt['short'],)
906 if opt.get('long', None):
908 if opt.get("optType", None) == "parameter":
911 long = "%-*s" % (maxOptLen, long)
915 long = " " * (maxOptLen + len('--'))
917 if opt.get('optType', None) == 'command':
918 column1 = ' %s ' % long
920 column1 = " %2s%c --%s " % (short, comma, long)
922 if opt.get('doc', ''):
923 doc = opt['doc'].strip()
927 if (opt.get("optType", None) == "parameter") \
928 and not (opt.get('default', None) is None):
929 doc = "%s [default: %s]" % (doc, opt['default'])
931 if (opt.get("optType", None) == "parameter") \
932 and opt.get('dispatch', None) is not None:
934 if isinstance(d, CoerceParameter) and d.doc:
935 doc = "%s. %s" % (doc, d.doc)
938 column2_l = text.wordWrap(doc, colWidth2)
942 optLines.append("%s%s\n" % (column1, column2_l.pop(0)))
944 for line in column2_l:
945 optLines.append("%s%s\n" % (colFiller1, line))
947 optChunks.append(''.join(optLines))
952 def flagFunction(method, name=None):
953 reqArgs = method.im_func.func_code.co_argcount
955 raise UsageError('Invalid Option function for %s' %
956 (name or method.func_name))
958 # argName = method.im_func.func_code.co_varnames[1]
963 def portCoerce(value):
965 Coerce a string value to an int port number, and checks the validity.
968 if value < 0 or value > 65535:
969 raise ValueError("Port number not in range: %s" % (value,))
971 portCoerce.coerceDoc = "Must be an int between 0 and 65535."