1 """ CommandLine - Get and parse command line options
3 NOTE: This still is very much work in progress !!!
5 Different version are likely to be incompatible.
9 * Incorporate the changes made by (see Inbox)
10 * Add number range option using srange()
15 Copyright (c), 1997-2006, Marc-Andre Lemburg (mal@lemburg.com)
16 Copyright (c), 2000-2006, eGenix.com Software GmbH (info@egenix.com)
17 See the documentation for further information on copyrights,
18 or contact the author. All Rights Reserved.
23 import sys
, getopt
, string
, glob
, os
, re
, exceptions
, traceback
27 def _getopt_flags(options
):
29 """ Convert the option list to a getopt flag string and long opt
47 return string
.join(s
,''),l
49 def invisible_input(prompt
='>>> '):
51 """ Get raw input from a terminal without echoing the characters to
52 the terminal, e.g. for password queries.
56 entry
= getpass
.getpass(prompt
)
58 raise KeyboardInterrupt
61 def fileopen(name
, mode
='wb', encoding
=None):
63 """ Open a file using mode.
65 Default mode is 'wb' meaning to open the file for writing in
66 binary mode. If encoding is given, I/O to and from the file is
67 transparently encoded using the given encoding.
69 Files opened for writing are chmod()ed to 0600.
74 elif name
== 'stderr':
79 if encoding
is not None:
81 f
= codecs
.open(name
, mode
, encoding
)
88 def option_dict(options
):
90 """ Return a dictionary mapping option names to Option instances.
93 for option
in options
:
94 d
[option
.name
] = option
98 getpasswd
= invisible_input
100 _integerRE
= re
.compile('\s*(-?\d+)\s*$')
101 _integerRangeRE
= re
.compile('\s*(-?\d+)\s*-\s*(-?\d+)\s*$')
105 split
=string
.split
,integer
=_integerRE
,
106 integerRange
=_integerRangeRE
):
108 """ Converts a textual representation of integer numbers and ranges
111 Supported formats: 2,3,4,2-10,-1 - -3, 5 - -2
113 Values are appended to the created list in the order specified
119 for entry
in split(s
,','):
120 m
= integer
.match(entry
)
122 append(int(m
.groups()[0]))
124 m
= integerRange
.match(entry
)
126 start
,end
= map(int,m
.groups())
127 l
[len(l
):] = range(start
,end
+1)
132 expandvars
=os
.path
.expandvars
,expanduser
=os
.path
.expanduser
,
133 join
=os
.path
.join
,getcwd
=os
.getcwd
):
135 """ Return the corresponding absolute path for path.
137 path is expanded in the usual shell ways before
138 joining it with the current working directory.
142 path
= expandvars(path
)
143 except AttributeError:
146 path
= expanduser(path
)
147 except AttributeError:
149 return join(getcwd(), path
)
155 """ Option base class. Takes no argument.
165 def __init__(self
,name
,help=None):
167 if not name
[:1] == '-':
168 raise TypeError,'option names must start with "-"'
180 name
= o
.prefix
+ o
.name
183 if len(name
) > self
.tab
:
184 name
= name
+ '\n' + ' ' * (self
.tab
+ 1 + len(o
.prefix
))
186 name
= '%-*s ' % (self
.tab
, name
)
189 description
= description
+ ' (%s)' % o
.default
190 return '%s %s' % (name
, description
)
192 class ArgumentOption(Option
):
194 """ Option that takes an argument.
196 An optional default argument can be given.
199 def __init__(self
,name
,help=None,default
=None):
202 Option
.__init
__(self
,name
,help)
204 if default
is not None:
205 self
.default
= default
207 self
.takes_argument
= 1
209 class SwitchOption(Option
):
211 """ Options that can be on or off. Has an optional default value.
214 def __init__(self
,name
,help=None,default
=None):
217 Option
.__init
__(self
,name
,help)
219 if default
is not None:
220 self
.default
= default
223 ### Application baseclass
227 """ Command line application interface with builtin argument
231 # Options the program accepts (Option instances)
234 # Standard settings; these are appended to options in __init__
235 preset_options
= [SwitchOption('-v',
236 'generate verbose output'),
238 'show this help text'),
239 SwitchOption('--help',
240 'show this help text'),
241 SwitchOption('--debug',
243 SwitchOption('--copyright',
245 SwitchOption('--examples',
246 'show examples of usage')]
248 # The help layout looks like this:
249 # [header] - defaults to ''
251 # [synopsis] - formatted as '<self.name> %s' % self.synopsis
254 # [options] - formatted from self.options
256 # [version] - formatted as 'Version:\n %s' % self.version, if given
258 # [about] - defaults to ''
260 # Note: all fields that do not behave as template are formatted
261 # using the instances dictionary as substitution namespace,
262 # e.g. %(name)s will be replaced by the applications name.
265 # Header (default to program name)
268 # Name (defaults to program name)
271 # Synopsis (%(name)s is replaced by the program name)
272 synopsis
= '%(name)s [option] files...'
277 # General information printed after the possible options (optional)
280 # Examples of usage to show when the --examples option is given (optional)
284 copyright
= __copyright__
286 # Apply file globbing ?
289 # Generate debug output ?
292 # Generate verbose output ?
295 # Internal errors to catch
296 InternalError
= exceptions
.Exception
298 # Instance variables:
299 values
= None # Dictionary of passed options (or default values)
300 # indexed by the options name, e.g. '-h'
301 files
= None # List of passed filenames
302 optionlist
= None # List of passed options
304 def __init__(self
,argv
=None):
306 # Setup application specs
309 self
.filename
= os
.path
.split(argv
[0])[1]
311 self
.name
= os
.path
.split(self
.filename
)[1]
313 self
.name
= self
.name
315 self
.header
= self
.name
317 self
.header
= self
.header
319 # Init .arguments list
320 self
.arguments
= argv
[1:]
322 # Setup Option mapping
323 self
.option_map
= option_dict(self
.options
)
325 # Append preset options
326 for option
in self
.preset_options
:
327 if not self
.option_map
.has_key(option
.name
):
328 self
.add_option(option
)
350 except SystemExit,rc
:
353 except KeyboardInterrupt:
359 except self
.InternalError
:
361 print '* Internal Error (use --debug to display the traceback)'
364 traceback
.print_exc(20, sys
.stdout
)
366 print ' %s: %s' % sys
.exc_info()[:2]
372 def add_option(self
, option
):
374 """ Add a new Option instance to the Application dynamically.
376 Note that this has to be done *before* .parse() is being
380 self
.options
.append(option
)
381 self
.option_map
[option
.name
] = option
385 """ Set user defined instance variables.
387 If this method returns anything other than None, the
388 process is terminated with the return value as exit code.
393 def exit(self
, rc
=0):
395 """ Exit the program.
397 rc is used as exit code and passed back to the calling
398 program. It defaults to 0 which usually means: OK.
405 """ Parse the command line and fill in self.values and self.files.
407 After having parsed the options, the remaining command line
408 arguments are interpreted as files and passed to .handle_files()
411 As final step the option handlers are called in the order
412 of the options given on the command line.
416 self
.values
= values
= {}
417 for o
in self
.options
:
419 values
[o
.prefix
+o
.name
] = o
.default
421 values
[o
.prefix
+o
.name
] = 0
422 flags
,lflags
= _getopt_flags(self
.options
)
424 optlist
,files
= getopt
.getopt(self
.arguments
,flags
,lflags
)
434 self
.optionlist
= optlist
435 self
.files
= files
+ self
.files
436 except getopt
.error
,why
:
441 rc
= self
.handle_files(self
.files
)
445 # Call option handlers
446 for optionname
, value
in optlist
:
448 # Try to convert value to integer
450 value
= string
.atoi(value
)
454 # Find handler and call it (or count the number of option
455 # instances on the command line)
456 handlername
= 'handle' + string
.replace(optionname
, '-', '_')
458 handler
= getattr(self
, handlername
)
459 except AttributeError:
461 # count the number of occurances
462 if values
.has_key(optionname
):
463 values
[optionname
] = values
[optionname
] + 1
465 values
[optionname
] = 1
467 values
[optionname
] = value
473 # Apply final file check (for backward compatibility)
474 rc
= self
.check_files(self
.files
)
478 def check_files(self
,filelist
):
480 """ Apply some user defined checks on the files given in filelist.
482 This may modify filelist in place. A typical application
483 is checking that at least n files are given.
485 If this method returns anything other than None, the
486 process is terminated with the return value as exit code.
491 def help(self
,note
=''):
496 # To remain backward compatible:
498 synopsis
= self
.synopsis
% self
.name
499 except (NameError, KeyError, TypeError):
500 synopsis
= self
.synopsis
% self
.__dict
__
506 print ' %s' % self
.version
509 print string
.strip(self
.about
% self
.__dict
__)
516 def notice(self
,note
):
523 def print_header(self
):
526 print self
.header
% self
.__dict
__
530 def print_options(self
):
532 options
= self
.options
533 print 'Options and default settings:'
537 long = filter(lambda x
: x
.prefix
== '--', options
)
538 short
= filter(lambda x
: x
.prefix
== '-', options
)
547 # If a handler returns anything other than None, processing stops
548 # and the return value is passed to sys.exit() as argument.
552 def handle_files(self
,files
):
554 """ This may process the files list in place.
558 # Short option handler
559 def handle_h(self
,arg
):
564 def handle_v(self
, value
):
566 """ Turn on verbose output.
570 # Handlers for long options have two underscores in their name
571 def handle__help(self
,arg
):
576 def handle__debug(self
,arg
):
579 # We don't want to catch internal errors:
580 self
.InternalError
= None
582 def handle__copyright(self
,arg
):
585 print string
.strip(self
.copyright
% self
.__dict
__)
589 def handle__examples(self
,arg
):
595 print string
.strip(self
.examples
% self
.__dict
__)
598 print 'No examples available.'
604 """ Override this method as program entry point.
606 The return value is passed to sys.exit() as argument. If
607 it is None, 0 is assumed (meaning OK). Unhandled
608 exceptions are reported with exit status code 1 (see
609 __init__ for further details).
615 CommandLine
= Application
619 class MyApplication(Application
):
620 header
= 'Test Application'
621 version
= __version__
622 options
= [Option('-v','verbose')]
624 def handle_v(self
,arg
):
625 print 'VERBOSE, Yeah !'
627 cmd
= MyApplication()
628 if not cmd
.values
['-h']:
630 print 'files:',cmd
.files
633 if __name__
== '__main__':