1 """Command-line options parser.
2 With the help of an options spec string, easily parse command-line options.
4 An options spec is made up of two parts, separated by a line with two dashes.
5 The first part is the synopsis of the command and the second one specifies
8 Each non-empty line in the synopsis gives a set of options that can be used
11 Option flags must be at the begining of the line and multiple flags are
12 separated by commas. Usually, options have a short, one character flag, and a
13 longer one, but the short one can be omitted.
15 Long option flags are used as the option's key for the OptDict produced when
18 When the flag definition is ended with an equal sign, the option takes one
19 string as an argument. Otherwise, the option does not take an argument and
20 corresponds to a boolean flag that is true when the option is given on the
23 The option's description is found at the right of its flags definition, after
24 one or more spaces. The description ends at the end of the line. If the
25 description contains text enclosed in square brackets, the enclosed text will
26 be used as the option's default value.
28 Options can be put in different groups. Options in the same group must be on
29 consecutive lines. Groups are formed by inserting a line that begins with a
30 space. The text on that line will be output after an empty line.
32 import sys, os, textwrap, getopt, re, struct
35 """Dictionary that exposes keys as attributes.
37 Keys can bet set or accessed with a "no-" or "no_" prefix to negate the
43 def __setitem__(self, k, v):
44 if k.startswith('no-') or k.startswith('no_'):
49 def __getitem__(self, k):
50 if k.startswith('no-') or k.startswith('no_'):
51 return not self._opts[k[3:]]
54 def __getattr__(self, k):
58 def _default_onabort(msg):
79 def _remove_negative_kv(k, v):
80 if k.startswith('no-') or k.startswith('no_'):
84 def _remove_negative_k(k):
85 return _remove_negative_kv(k, None)[0]
89 s = struct.pack("HHHH", 0, 0, 0, 0)
92 s = fcntl.ioctl(sys.stderr.fileno(), termios.TIOCGWINSZ, s)
93 except (IOError, ImportError):
94 return _atoi(os.environ.get('WIDTH')) or 70
95 (ysize,xsize,ypix,xpix) = struct.unpack('HHHH', s)
101 When constructed, a string called an option spec must be given. It
102 specifies the synopsis and option flags and their description. For more
103 information about option specs, see the docstring at the top of this file.
105 Two optional arguments specify an alternative parsing function and an
106 alternative behaviour on abort (after having output the usage string).
108 By default, the parser function is getopt.gnu_getopt, and the abort
109 behaviour is to exit the program.
111 def __init__(self, optspec, optfunc=getopt.gnu_getopt,
112 onabort=_default_onabort):
113 self.optspec = optspec
114 self._onabort = onabort
115 self.optfunc = optfunc
117 self._shortopts = 'h?'
118 self._longopts = ['help']
121 self._usagestr = self._gen_usage()
123 def _gen_usage(self):
125 lines = self.optspec.strip().split('\n')
131 out.append('%s: %s\n' % (first_syn and 'usage' or ' or', l))
134 last_was_option = False
137 if l.startswith(' '):
138 out.append('%s%s\n' % (last_was_option and '\n' or '',
140 last_was_option = False
142 (flags, extra) = l.split(' ', 1)
143 extra = extra.strip()
144 if flags.endswith('='):
149 g = re.search(r'\[([^\]]*)\]$', extra)
154 flagl = flags.split(',')
157 f,dvi = _remove_negative_kv(_f, _intify(defval))
158 self._aliases[f] = _remove_negative_k(flagl[0])
159 self._hasparms[f] = has_parm
160 self._defaults[f] = dvi
162 self._shortopts += f + (has_parm and ':' or '')
163 flagl_nice.append('-' + f)
165 f_nice = re.sub(r'\W', '_', f)
166 self._aliases[f_nice] = _remove_negative_k(flagl[0])
167 self._longopts.append(f + (has_parm and '=' or ''))
168 self._longopts.append('no-' + f)
169 flagl_nice.append('--' + _f)
170 flags_nice = ', '.join(flagl_nice)
173 prefix = ' %-20s ' % flags_nice
174 argtext = '\n'.join(textwrap.wrap(extra, width=_tty_width(),
175 initial_indent=prefix,
176 subsequent_indent=' '*28))
177 out.append(argtext + '\n')
178 last_was_option = True
181 last_was_option = False
182 return ''.join(out).rstrip() + '\n'
184 def usage(self, msg=""):
185 """Print usage string to stderr and abort."""
186 sys.stderr.write(self._usagestr)
187 e = self._onabort and self._onabort(msg) or None
192 """Print an error message to stderr and abort with usage string."""
193 msg = 'error: %s\n' % s
194 sys.stderr.write(msg)
195 return self.usage(msg)
197 def parse(self, args):
198 """Parse a list of arguments and return (options, flags, extra).
200 In the returned tuple, "options" is an OptDict with known options,
201 "flags" is a list of option flags that were used on the command-line,
202 and "extra" is a list of positional arguments.
205 (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
206 except getopt.GetoptError, e:
211 for k,v in self._defaults.iteritems():
217 if k in ('h', '?', 'help'):
219 if k.startswith('no-'):
220 k = self._aliases[k[3:]]
224 if not self._hasparms[k]:
226 v = (opt._opts.get(k) or 0) + 1
230 for (f1,f2) in self._aliases.iteritems():
231 opt[f1] = opt._opts.get(f2)
232 return (opt,flags,extra)