~ipython-contrib/+junk/ipython-zmq

« back to all changes in this revision

Viewing changes to IPython/DPyGetOpt.py

  • Committer: ville
  • Date: 2008-02-16 09:50:47 UTC
  • mto: (0.12.1 ipython_main)
  • mto: This revision was merged to the branch mainline in revision 990.
  • Revision ID: ville@ville-pc-20080216095047-500x6dluki1iz40o
initialization (no svn history)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""DPyGetOpt -- Demiurge Python GetOptions Module
 
3
 
 
4
 $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $
 
5
 
 
6
This module is modeled after perl's Getopt::Long module-- which
 
7
is, in turn, modeled after GNU's extended getopt() function.
 
8
 
 
9
Upon instantiation, the option specification should be a sequence
 
10
(list) of option definitions.
 
11
 
 
12
Options that take no arguments should simply contain the name of
 
13
the option.  If a ! is post-pended, the option can be negated by
 
14
prepending 'no';  ie 'debug!' specifies that -debug and -nodebug
 
15
should be accepted.
 
16
 
 
17
Mandatory arguments to options are specified using a postpended
 
18
'=' + a type specifier.  '=s' specifies a mandatory string
 
19
argument, '=i' specifies a mandatory integer argument, and '=f'
 
20
specifies a mandatory real number.  In all cases, the '=' can be
 
21
substituted with ':' to specify that the argument is optional.
 
22
 
 
23
Dashes '-' in option names are allowed.
 
24
 
 
25
If an option has the character '@' postpended (after the
 
26
argumentation specification), it can appear multiple times within
 
27
each argument list that is processed. The results will be stored
 
28
in a list.
 
29
 
 
30
The option name can actually be a list of names separated by '|'
 
31
characters;  ie-- 'foo|bar|baz=f@' specifies that all -foo, -bar,
 
32
and -baz options that appear on within the parsed argument list
 
33
must have a real number argument and that the accumulated list
 
34
of values will be available under the name 'foo'
 
35
 
 
36
$Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z fperez $"""
 
37
 
 
38
#*****************************************************************************
 
39
#
 
40
# Copyright (c) 2001 Bill Bumgarner <bbum@friday.com>
 
41
#
 
42
#
 
43
# Published under the terms of the MIT license, hereby reproduced:
 
44
#
 
45
# Permission is hereby granted, free of charge, to any person obtaining a copy
 
46
# of this software and associated documentation files (the "Software"), to
 
47
# deal in the Software without restriction, including without limitation the
 
48
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 
49
# sell copies of the Software, and to permit persons to whom the Software is
 
50
# furnished to do so, subject to the following conditions:
 
51
#
 
52
# The above copyright notice and this permission notice shall be included in
 
53
# all copies or substantial portions of the Software.
 
54
#
 
55
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
56
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
57
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
58
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
59
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
60
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
61
# IN THE SOFTWARE.
 
62
#
 
63
#*****************************************************************************
 
64
 
 
65
__author__  = 'Bill Bumgarner <bbum@friday.com>'
 
66
__license__ = 'MIT'
 
67
__version__ = '1.2'
 
68
 
 
69
# Modified to use re instead of regex and regsub modules.
 
70
# 2001/5/7, Jonathan Hogg <jonathan@onegoodidea.com>
 
71
 
 
72
import re
 
73
import string
 
74
import sys
 
75
import types
 
76
 
 
77
class Error(Exception):
 
78
    """Base class for exceptions in the DPyGetOpt module."""
 
79
 
 
80
class ArgumentError(Error):
 
81
    """Exception indicating an error in the arguments passed to
 
82
    DPyGetOpt.processArguments."""
 
83
 
 
84
class SpecificationError(Error):
 
85
    """Exception indicating an error with an option specification."""
 
86
 
 
87
class TerminationError(Error):
 
88
    """Exception indicating an error with an option processing terminator."""
 
89
 
 
90
specificationExpr = re.compile('(?P<required>.)(?P<type>.)(?P<multi>@?)')
 
91
 
 
92
ArgRequired     = 'Requires an Argument'
 
93
ArgOptional     = 'Argument Optional'
 
94
 
 
95
# The types modules is not used for these identifiers because there
 
96
# is no identifier for 'boolean' or 'generic'
 
97
StringArgType   = 'String Argument Type'
 
98
IntegerArgType  = 'Integer Argument Type'
 
99
RealArgType             = 'Real Argument Type'
 
100
BooleanArgType  = 'Boolean Argument Type'
 
101
GenericArgType  = 'Generic Argument Type'
 
102
 
 
103
# dictionary of conversion functions-- boolean and generic options
 
104
# do not accept arguments and do not need conversion functions;
 
105
# the identity function is used purely for convenience.
 
106
ConversionFunctions = {
 
107
        StringArgType : lambda x: x,
 
108
        IntegerArgType : string.atoi,
 
109
        RealArgType : string.atof,
 
110
        BooleanArgType : lambda x: x,
 
111
        GenericArgType : lambda x: x,
 
112
        }
 
113
 
 
114
class DPyGetOpt:
 
115
 
 
116
    def __init__(self, spec = None, terminators = ['--']):
 
117
        """
 
118
        Declare and intialize instance variables
 
119
 
 
120
        Yes, declaration is not necessary... but one of the things
 
121
        I sorely miss from C/Obj-C is the concept of having an
 
122
        interface definition that clearly declares all instance
 
123
        variables and methods without providing any implementation
 
124
         details.   it is a useful reference!
 
125
 
 
126
        all instance variables are initialized to 0/Null/None of
 
127
        the appropriate type-- not even the default value...
 
128
        """
 
129
 
 
130
#               sys.stderr.write(string.join(spec) + "\n")
 
131
 
 
132
        self.allowAbbreviations = 1  # boolean, 1 if abbreviations will
 
133
                                                                                  # be expanded
 
134
        self.freeValues         = [] # list, contains free values
 
135
        self.ignoreCase         = 0  # boolean, YES if ignoring case
 
136
        self.needsParse         = 0  # boolean, YES if need to reparse parameter spec
 
137
        self.optionNames        = {} # dict, all option names-- value is index of tuple
 
138
        self.optionStartExpr    = None # regexp defining the start of an option (ie; '-', '--')
 
139
        self.optionTuples       = [] # list o' tuples containing defn of options AND aliases
 
140
        self.optionValues       = {} # dict, option names (after alias expansion) -> option value(s)
 
141
        self.orderMixed         = 0  # boolean, YES if options can be mixed with args
 
142
        self.posixCompliance    = 0  # boolean, YES indicates posix like behaviour
 
143
        self.spec               = [] # list, raw specs (in case it must be reparsed)
 
144
        self.terminators        = terminators # list, strings that terminate argument processing
 
145
        self.termValues         = [] # list, values after terminator
 
146
        self.terminator         = None # full name of terminator that ended
 
147
                                               # option processing
 
148
 
 
149
        # set up defaults
 
150
        self.setPosixCompliance()
 
151
        self.setIgnoreCase()
 
152
        self.setAllowAbbreviations()
 
153
 
 
154
        # parse spec-- if present
 
155
        if spec:
 
156
            self.parseConfiguration(spec)
 
157
 
 
158
    def setPosixCompliance(self, aFlag = 0):
 
159
        """
 
160
        Enables and disables posix compliance.
 
161
 
 
162
        When enabled, '+' can be used as an option prefix and free
 
163
        values can be mixed with options.
 
164
        """
 
165
        self.posixCompliance = aFlag
 
166
        self.needsParse = 1
 
167
 
 
168
        if self.posixCompliance:
 
169
            self.optionStartExpr = re.compile('(--|-)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
 
170
            self.orderMixed = 0
 
171
        else:
 
172
            self.optionStartExpr = re.compile('(--|-|\+)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
 
173
            self.orderMixed = 1
 
174
 
 
175
    def isPosixCompliant(self):
 
176
        """
 
177
        Returns the value of the posix compliance flag.
 
178
        """
 
179
        return self.posixCompliance
 
180
 
 
181
    def setIgnoreCase(self, aFlag = 1):
 
182
        """
 
183
        Enables and disables ignoring case during option processing.
 
184
        """
 
185
        self.needsParse = 1
 
186
        self.ignoreCase = aFlag
 
187
 
 
188
    def ignoreCase(self):
 
189
        """
 
190
        Returns 1 if the option processor will ignore case when
 
191
        processing options.
 
192
        """
 
193
        return self.ignoreCase
 
194
 
 
195
    def setAllowAbbreviations(self, aFlag = 1):
 
196
        """
 
197
        Enables and disables the expansion of abbreviations during
 
198
        option processing.
 
199
        """
 
200
        self.allowAbbreviations = aFlag
 
201
 
 
202
    def willAllowAbbreviations(self):
 
203
        """
 
204
        Returns 1 if abbreviated options will be automatically
 
205
        expanded to the non-abbreviated form (instead of causing an
 
206
        unrecognized option error).
 
207
        """
 
208
        return self.allowAbbreviations
 
209
 
 
210
    def addTerminator(self, newTerm):
 
211
        """
 
212
        Adds newTerm as terminator of option processing.
 
213
 
 
214
        Whenever the option processor encounters one of the terminators
 
215
        during option processing, the processing of options terminates
 
216
        immediately, all remaining options are stored in the termValues
 
217
        instance variable and the full name of the terminator is stored
 
218
        in the terminator instance variable.
 
219
        """
 
220
        self.terminators = self.terminators + [newTerm]
 
221
 
 
222
    def _addOption(self, oTuple):
 
223
        """
 
224
        Adds the option described by oTuple (name, (type, mode,
 
225
        default), alias) to optionTuples.  Adds index keyed under name
 
226
        to optionNames.  Raises SpecificationError if name already in
 
227
        optionNames
 
228
        """
 
229
        (name, (type, mode, default, multi), realName) = oTuple
 
230
 
 
231
        # verify name and add to option names dictionary
 
232
        if self.optionNames.has_key(name):
 
233
            if realName:
 
234
                raise SpecificationError('Alias \'' + name + '\' for \'' +
 
235
                                         realName +
 
236
                                         '\' already used for another option or alias.')
 
237
            else:
 
238
                raise SpecificationError('Option named \'' + name +
 
239
                                         '\' specified more than once. Specification: '
 
240
                                         + option)
 
241
 
 
242
        # validated. add to optionNames
 
243
        self.optionNames[name] = self.tupleIndex
 
244
        self.tupleIndex = self.tupleIndex + 1
 
245
 
 
246
        # add to optionTuples
 
247
        self.optionTuples = self.optionTuples + [oTuple]
 
248
 
 
249
        # if type is boolean, add negation
 
250
        if type == BooleanArgType:
 
251
            alias            = 'no' + name
 
252
            specTuple = (type, mode, 0, multi)
 
253
            oTuple = (alias, specTuple, name)
 
254
 
 
255
            # verify name and add to option names dictionary
 
256
            if self.optionNames.has_key(alias):
 
257
                if realName:
 
258
                    raise SpecificationError('Negated alias \'' + name +
 
259
                                             '\' for \'' + realName +
 
260
                                             '\' already used for another option or alias.')
 
261
                else:
 
262
                    raise SpecificationError('Negated option named \'' + name +
 
263
                                             '\' specified more than once. Specification: '
 
264
                                             + option)
 
265
 
 
266
            # validated. add to optionNames
 
267
            self.optionNames[alias] = self.tupleIndex
 
268
            self.tupleIndex = self.tupleIndex + 1
 
269
 
 
270
            # add to optionTuples
 
271
            self.optionTuples = self.optionTuples + [oTuple]
 
272
 
 
273
    def addOptionConfigurationTuple(self, oTuple):
 
274
        (name, argSpec, realName) = oTuple
 
275
        if self.ignoreCase:
 
276
            name = string.lower(name)
 
277
            if realName:
 
278
                realName = string.lower(realName)
 
279
            else:
 
280
                realName = name
 
281
 
 
282
            oTuple = (name, argSpec, realName)
 
283
 
 
284
        # add option
 
285
        self._addOption(oTuple)
 
286
 
 
287
    def addOptionConfigurationTuples(self, oTuple):
 
288
        if type(oTuple) is ListType:
 
289
            for t in oTuple:
 
290
                self.addOptionConfigurationTuple(t)
 
291
        else:
 
292
            self.addOptionConfigurationTuple(oTuple)
 
293
 
 
294
    def parseConfiguration(self, spec):
 
295
        # destroy previous stored information + store raw spec
 
296
        self.spec                       = spec
 
297
        self.optionTuples       = []
 
298
        self.optionNames  = {}
 
299
        self.tupleIndex   = 0
 
300
 
 
301
        tupleIndex = 0
 
302
 
 
303
        # create some regex's for parsing each spec
 
304
        splitExpr = \
 
305
                                 re.compile('(?P<names>\w+[-A-Za-z0-9|]*)?(?P<spec>!|[=:][infs]@?)?')
 
306
        for option in spec:
 
307
 # push to lower case (does not negatively affect
 
308
 # specification)
 
309
            if self.ignoreCase:
 
310
                option = string.lower(option)
 
311
 
 
312
            # break into names, specification
 
313
            match = splitExpr.match(option)
 
314
            if match is None:
 
315
                raise SpecificationError('Invalid specification {' + option +
 
316
                                         '}')
 
317
 
 
318
            names                     = match.group('names')
 
319
            specification = match.group('spec')
 
320
 
 
321
            # break name into name, aliases
 
322
            nlist = string.split(names, '|')
 
323
 
 
324
            # get name
 
325
            name      = nlist[0]
 
326
            aliases = nlist[1:]
 
327
 
 
328
            # specificationExpr = regex.symcomp('\(<required>.\)\(<type>.\)\(<multi>@?\)')
 
329
            if not specification:
 
330
                #spec tuple is ('type', 'arg mode', 'default value', 'multiple')
 
331
                argType         = GenericArgType
 
332
                argMode         = None
 
333
                argDefault      = 1
 
334
                argMultiple     = 0
 
335
            elif specification == '!':
 
336
                argType         = BooleanArgType
 
337
                argMode         = None
 
338
                argDefault      = 1
 
339
                argMultiple     = 0
 
340
            else:
 
341
                # parse
 
342
                match = specificationExpr.match(specification)
 
343
                if match is None:
 
344
                    # failed to parse, die
 
345
                    raise SpecificationError('Invalid configuration for option \''
 
346
                                             + option + '\'')
 
347
 
 
348
                # determine mode
 
349
                required = match.group('required')
 
350
                if required == '=':
 
351
                    argMode = ArgRequired
 
352
                elif required == ':':
 
353
                    argMode = ArgOptional
 
354
                else:
 
355
                    raise SpecificationError('Unknown requirement configuration \''
 
356
                                             + required + '\'')
 
357
 
 
358
                # determine type
 
359
                type = match.group('type')
 
360
                if type == 's':
 
361
                    argType   = StringArgType
 
362
                    argDefault = ''
 
363
                elif type == 'i':
 
364
                    argType   = IntegerArgType
 
365
                    argDefault = 1
 
366
                elif type == 'f' or type == 'n':
 
367
                    argType   = RealArgType
 
368
                    argDefault = 1
 
369
                else:
 
370
                    raise SpecificationError('Unknown type specifier \'' +
 
371
                                             type + '\'')
 
372
 
 
373
                # determine quantity
 
374
                if match.group('multi') == '@':
 
375
                    argMultiple = 1
 
376
                else:
 
377
                    argMultiple = 0
 
378
            ## end else (of not specification)
 
379
 
 
380
            # construct specification tuple
 
381
            specTuple = (argType, argMode, argDefault, argMultiple)
 
382
 
 
383
            # add the option-- option tuple is (name, specTuple, real name)
 
384
            oTuple = (name, specTuple, name)
 
385
            self._addOption(oTuple)
 
386
 
 
387
            for alias in aliases:
 
388
                # drop to all lower (if configured to do so)
 
389
                if self.ignoreCase:
 
390
                    alias = string.lower(alias)
 
391
                # create configuration tuple
 
392
                oTuple = (alias, specTuple, name)
 
393
                # add
 
394
                self._addOption(oTuple)
 
395
 
 
396
        # successfully parsed....
 
397
        self.needsParse = 0
 
398
 
 
399
    def _getArgTuple(self, argName):
 
400
        """
 
401
        Returns a list containing all the specification tuples that
 
402
        match argName.  If none match, None is returned.  If one
 
403
        matches, a list with one tuple is returned.  If more than one
 
404
        match, a list containing all the tuples that matched is
 
405
        returned.
 
406
 
 
407
        In other words, this function does not pass judgement upon the
 
408
        validity of multiple matches.
 
409
        """
 
410
        # is it in the optionNames dict?
 
411
 
 
412
        try:
 
413
#                       sys.stderr.write(argName + string.join(self.optionNames.keys()) + "\n")
 
414
 
 
415
            # yes, get index
 
416
            tupleIndex = self.optionNames[argName]
 
417
            # and return tuple as element of list
 
418
            return [self.optionTuples[tupleIndex]]
 
419
        except KeyError:
 
420
            # are abbreviations allowed?
 
421
            if not self.allowAbbreviations:
 
422
                # No! terefore, this cannot be valid argument-- nothing found
 
423
                return None
 
424
 
 
425
        # argName might be an abbreviation (and, abbreviations must
 
426
        # be allowed... or this would not have been reached!)
 
427
 
 
428
        # create regex for argName
 
429
        argExpr = re.compile('^' + argName)
 
430
 
 
431
        tuples = filter(lambda x, argExpr=argExpr: argExpr.search(x[0]) is not None,
 
432
                                                  self.optionTuples)
 
433
 
 
434
        if not len(tuples):
 
435
            return None
 
436
        else:
 
437
            return tuples
 
438
 
 
439
    def _isTerminator(self, optionName):
 
440
        """
 
441
        Returns the full name of the terminator if optionName is a valid
 
442
        terminator.  If it is, sets self.terminator to the full name of
 
443
        the terminator.
 
444
 
 
445
        If more than one terminator matched, raises a TerminationError with a
 
446
        string describing the ambiguity.
 
447
        """
 
448
 
 
449
#               sys.stderr.write(optionName + "\n")
 
450
#               sys.stderr.write(repr(self.terminators))
 
451
 
 
452
        if optionName in self.terminators:
 
453
            self.terminator = optionName
 
454
        elif not self.allowAbbreviations:
 
455
            return None
 
456
 
 
457
# regex thing in bogus
 
458
#               termExpr = regex.compile('^' + optionName)
 
459
 
 
460
        terms = filter(lambda x, on=optionName: string.find(x,on) == 0, self.terminators)
 
461
 
 
462
        if not len(terms):
 
463
            return None
 
464
        elif len(terms) > 1:
 
465
            raise TerminationError('Ambiguous terminator \'' + optionName +
 
466
                                   '\' matches ' + repr(terms))
 
467
 
 
468
        self.terminator = terms[0]
 
469
        return self.terminator
 
470
 
 
471
    def processArguments(self, args = None):
 
472
        """
 
473
        Processes args, a list of arguments (including options).
 
474
 
 
475
        If args is the same as sys.argv, automatically trims the first
 
476
        argument (the executable name/path).
 
477
 
 
478
        If an exception is not raised, the argument list was parsed
 
479
        correctly.
 
480
 
 
481
        Upon successful completion, the freeValues instance variable
 
482
        will contain all the arguments that were not associated with an
 
483
        option in the order they were encountered.  optionValues is a
 
484
        dictionary containing the value of each option-- the method
 
485
        valueForOption() can be used to query this dictionary.
 
486
        terminator will contain the argument encountered that terminated
 
487
        option processing (or None, if a terminator was never
 
488
        encountered) and termValues will contain all of the options that
 
489
        appeared after the Terminator (or an empty list).
 
490
        """
 
491
 
 
492
        if hasattr(sys, "argv") and args == sys.argv:
 
493
            args = sys.argv[1:]
 
494
 
 
495
        max             = len(args) # maximum index + 1
 
496
        self.freeValues = []        # array to hold return values
 
497
        self.optionValues= {}
 
498
        index           = 0         # initial index
 
499
        self.terminator = None
 
500
        self.termValues  = []
 
501
 
 
502
        while index < max:
 
503
            # obtain argument
 
504
            arg = args[index]
 
505
            # increment index -- REMEMBER; it is NOW incremented
 
506
            index = index + 1
 
507
 
 
508
            # terminate immediately if option terminator encountered
 
509
            if self._isTerminator(arg):
 
510
                self.freeValues = self.freeValues + args[index:]
 
511
                self.termValues = args[index:]
 
512
                return
 
513
 
 
514
            # is this possibly an option?
 
515
            match = self.optionStartExpr.match(arg)
 
516
            if match is None:
 
517
                # not an option-- add to freeValues
 
518
                self.freeValues = self.freeValues + [arg]
 
519
                if not self.orderMixed:
 
520
                    # mixing not allowed;  add rest of args as freeValues
 
521
                    self.freeValues = self.freeValues + args[index:]
 
522
                    # return to caller
 
523
                    return
 
524
                else:
 
525
                    continue
 
526
 
 
527
            # grab name
 
528
            optName = match.group('option')
 
529
 
 
530
            # obtain next argument-- index has already been incremented
 
531
            nextArg = match.group('arg')
 
532
            if nextArg:
 
533
                nextArg = nextArg[1:]
 
534
                index = index - 1 # put it back
 
535
            else:
 
536
                try:
 
537
                    nextArg = args[index]
 
538
                except:
 
539
                    nextArg = None
 
540
 
 
541
            # transpose to lower case, if necessary
 
542
            if self.ignoreCase:
 
543
                optName = string.lower(optName)
 
544
 
 
545
            # obtain defining tuple
 
546
            tuples = self._getArgTuple(optName)
 
547
 
 
548
            if tuples == None:
 
549
                raise ArgumentError('Illegal option \'' + arg + '\'')
 
550
            elif len(tuples) > 1:
 
551
                raise ArgumentError('Ambiguous option \'' + arg +
 
552
                                    '\';  matches ' +
 
553
                                    repr(map(lambda x: x[0], tuples)))
 
554
            else:
 
555
                config = tuples[0]
 
556
 
 
557
            # config is now set to the configuration tuple for the
 
558
            # argument
 
559
            (fullName, spec, realName) = config
 
560
            (optType, optMode, optDefault, optMultiple) = spec
 
561
 
 
562
            # if opt mode required, but nextArg is none, raise an error
 
563
            if (optMode == ArgRequired):
 
564
                if (not nextArg) or self._isTerminator(nextArg):
 
565
#                                       print nextArg
 
566
                    raise ArgumentError('Option \'' + arg +
 
567
                                        '\' requires an argument of type ' +
 
568
                                        optType)
 
569
 
 
570
            if (not optMode == None) and nextArg and (not self._isTerminator(nextArg)):
 
571
                # nextArg defined, option configured to possibly consume arg
 
572
                try:
 
573
                    # grab conversion function-- the try is more for internal diagnostics
 
574
                    func = ConversionFunctions[optType]
 
575
                    try:
 
576
                        optionValue = func(nextArg)
 
577
                        index = index + 1
 
578
                    except:
 
579
                        # only raise conversion error if REQUIRED to consume argument
 
580
                        if optMode == ArgRequired:
 
581
                            raise ArgumentError('Invalid argument to option \''
 
582
                                                + arg + '\';  should be \'' +
 
583
                                                optType + '\'')
 
584
                        else:
 
585
                            optionValue = optDefault
 
586
                except ArgumentError:
 
587
                    raise
 
588
                except:
 
589
                    raise ArgumentError('(' + arg +
 
590
                                        ') Conversion function for \'' +
 
591
                                        optType + '\' not found.')
 
592
            else:
 
593
                optionValue = optDefault
 
594
 
 
595
            # add value to options dictionary
 
596
            if optMultiple:
 
597
                # can be multiple values
 
598
                try:
 
599
                    # try to append element
 
600
                    self.optionValues[realName] = self.optionValues[realName] + [optionValue]
 
601
                except:
 
602
                    # failed-- must not exist;  add it
 
603
                    self.optionValues[realName] = [optionValue]
 
604
            else:
 
605
                # only one value per
 
606
                if self.isPosixCompliant and self.optionValues.has_key(realName):
 
607
                    raise ArgumentError('Argument \'' + arg +
 
608
                                        '\' occurs multiple times.')
 
609
 
 
610
                self.optionValues[realName] = optionValue
 
611
 
 
612
    def valueForOption(self, optionName, defaultValue = None):
 
613
        """
 
614
        Return the value associated with optionName.  If optionName was
 
615
        not encountered during parsing of the arguments, returns the
 
616
        defaultValue (which defaults to None).
 
617
        """
 
618
        try:
 
619
            optionValue = self.optionValues[optionName]
 
620
        except:
 
621
            optionValue = defaultValue
 
622
 
 
623
        return optionValue
 
624
 
 
625
##
 
626
## test/example section
 
627
##
 
628
test_error = 'Test Run Amok!'
 
629
def _test():
 
630
    """
 
631
    A relatively complete test suite.
 
632
    """
 
633
    try:
 
634
        DPyGetOpt(['foo', 'bar=s', 'foo'])
 
635
    except Error, exc:
 
636
        print 'EXCEPTION (should be \'foo\' already used..): %s' % exc
 
637
 
 
638
    try:
 
639
        DPyGetOpt(['foo|bar|apple=s@', 'baz|apple!'])
 
640
    except Error, exc:
 
641
        print 'EXCEPTION (should be duplicate alias/name error): %s' % exc
 
642
 
 
643
    x = DPyGetOpt(['apple|atlas=i@', 'application|executable=f@'])
 
644
    try:
 
645
        x.processArguments(['-app', '29.3'])
 
646
    except Error, exc:
 
647
        print 'EXCEPTION (should be ambiguous argument): %s' % exc
 
648
 
 
649
    x = DPyGetOpt(['foo'], ['antigravity', 'antithesis'])
 
650
    try:
 
651
        x.processArguments(['-foo', 'anti'])
 
652
    except Error, exc:
 
653
        print 'EXCEPTION (should be ambiguous terminator): %s' % exc
 
654
 
 
655
    profile = ['plain-option',
 
656
                              'boolean-option!',
 
657
                              'list-of-integers=i@',
 
658
                              'list-real-option|list-real-alias|list-real-pseudonym=f@',
 
659
                              'optional-string-option:s',
 
660
                              'abbreviated-string-list=s@']
 
661
 
 
662
    terminators = ['terminator']
 
663
 
 
664
    args = ['-plain-option',
 
665
                      '+noboolean-option',
 
666
                      '--list-of-integers', '1',
 
667
                      '+list-of-integers', '2',
 
668
                      '-list-of-integers', '3',
 
669
                      'freeargone',
 
670
                      '-list-real-option', '1.1',
 
671
                      '+list-real-alias', '1.2',
 
672
                      '--list-real-pseudonym', '1.3',
 
673
                      'freeargtwo',
 
674
                      '-abbreviated-string-list', 'String1',
 
675
                      '--abbreviated-s', 'String2',
 
676
                      '-abbrev', 'String3',
 
677
                      '-a', 'String4',
 
678
                      '-optional-string-option',
 
679
                      'term',
 
680
                      'next option should look like an invalid arg',
 
681
                      '-a']
 
682
 
 
683
 
 
684
    print 'Using profile: ' + repr(profile)
 
685
    print 'With terminator: ' + repr(terminators)
 
686
    print 'Processing arguments: ' + repr(args)
 
687
 
 
688
    go = DPyGetOpt(profile, terminators)
 
689
    go.processArguments(args)
 
690
 
 
691
    print 'Options (and values): ' + repr(go.optionValues)
 
692
    print 'free args: ' + repr(go.freeValues)
 
693
    print 'term args: ' + repr(go.termValues)