2 # pygobject - Python bindings for the GObject library
3 # Copyright (C) 2006 Johannes Hoelzl
5 # glib/option.py: GOption command line parser
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 """GOption command line parser
22 Extends optparse to use the GOptionGroup, GOptionEntry and GOptionContext
23 objects. So it is possible to use the gtk, gnome_program and gstreamer command
24 line groups and contexts.
26 Use this interface instead of the raw wrappers of GOptionContext and
32 from optparse import OptParseError, OptionError, OptionValueError, \
33 BadOptionError, OptionConflictError
34 from .module import get_introspection_module
36 if sys.version_info >= (3, 0):
38 _bytes = lambda s: s.encode()
40 _basestring = basestring
43 from gi._gi import _glib
44 from gi._error import GError
45 GLib = get_introspection_module('GLib')
47 OPTION_CONTEXT_ERROR_QUARK = GLib.quark_to_string(GLib.option_error_quark())
54 "OptionConflictError",
62 class Option(optparse.Option):
63 """Represents a command line option
65 To use the extended possibilities of the GOption API Option
66 (and make_option) are extended with new types and attributes.
69 filename The supplied arguments are read as filename, GOption
70 parses this type in with the GLib filename encoding.
73 This does not need a arguement, but it can be supplied.
75 The help list does not show this option
77 This option apears in the main group, this should only
78 be used for backwards compatibility.
80 Use Option.REMAINING as option name to get all positional arguments.
83 Every argument to an option is passed as utf-8 coded string, the only
84 exception are options which use the 'filename' type, its arguments
85 are passed as strings in the GLib filename encoding.
87 For further help, see optparse.Option.
89 TYPES = optparse.Option.TYPES + (
93 ATTRS = optparse.Option.ATTRS + [
99 REMAINING = '--' + GLib.OPTION_REMAINING
101 def __init__(self, *args, **kwargs):
102 optparse.Option.__init__(self, *args, **kwargs)
103 if not self._long_opts:
104 raise ValueError("%s at least one long option name.")
106 if len(self._long_opts) < len(self._short_opts):
108 "%s at least more long option names than short option names.")
111 raise ValueError("%s needs a help message.", self._long_opts[0])
113 def _set_opt_string(self, opts):
114 if self.REMAINING in opts:
115 self._long_opts.append(self.REMAINING)
116 optparse.Option._set_opt_string(self, opts)
117 if len(self._short_opts) > len(self._long_opts):
118 raise OptionError("goption.Option needs more long option names "
119 "than short option names")
121 def _to_goptionentries(self):
125 flags |= GLib.OptionFlags.HIDDEN
128 flags |= GLib.OptionFlags.IN_MAIN
130 if self.takes_value():
131 if self.optional_arg:
132 flags |= GLib.OptionFlags.OPTIONAL_ARG
134 flags |= GLib.OptionFlags.NO_ARG
136 if self.type == 'filename':
137 flags |= GLib.OptionFlags.FILENAME
139 for (long_name, short_name) in zip(self._long_opts, self._short_opts):
140 yield (long_name[2:], _bytes(short_name[1]), flags, self.help, self.metavar)
142 for long_name in self._long_opts[len(self._short_opts):]:
143 yield (long_name[2:], _bytes('\0'), flags, self.help, self.metavar)
146 class OptionGroup(optparse.OptionGroup):
147 """A group of command line options.
150 The groups name, used to create the --help-{name} option
151 :param str description:
152 Shown as title of the groups help view
153 :param str help_description:
154 Shown as help to the --help-{name} option
155 :param list option_list:
156 The options used in this group, must be option.Option()
157 :param dict defaults:
158 A dicitionary of default values
159 :param translation_domain:
160 Sets the translation domain for gettext().
163 This OptionGroup does not exactly map the optparse.OptionGroup
164 interface. There is no parser object to supply, but it is possible
165 to set default values and option_lists. Also the default values and
166 values are not shared with the OptionParser.
168 To pass a OptionGroup into a function which expects a GOptionGroup (e.g.
169 gnome_program_init() ). OptionGroup.get_option_group() can be used.
171 For further help, see optparse.OptionGroup.
173 def __init__(self, name, description, help_description="",
174 option_list=None, defaults=None,
175 translation_domain=None):
176 optparse.OptionContainer.__init__(self, Option, 'error', description)
179 self.help_description = help_description
181 self.defaults = defaults
185 self.translation_domain = translation_domain
188 for option in option_list:
189 self.add_option(option)
191 def _create_option_list(self):
192 self.option_list = []
193 self._create_option_mappings()
195 def _to_goptiongroup(self, parser):
196 def callback(option_name, option_value, group):
197 if option_name.startswith('--'):
198 opt = self._long_opt[option_name]
200 opt = self._short_opt[option_name]
203 opt.process(option_name, option_value, self.values, parser)
204 except OptionValueError:
205 error = sys.exc_info()[1]
206 gerror = GError(str(error))
207 gerror.domain = OPTION_CONTEXT_ERROR_QUARK
208 gerror.code = GLib.OptionError.BAD_VALUE
209 gerror.message = str(error)
212 group = _glib.OptionGroup(self.name, self.description,
213 self.help_description, callback)
214 if self.translation_domain:
215 group.set_translation_domain(self.translation_domain)
218 for option in self.option_list:
219 entries.extend(option._to_goptionentries())
221 group.add_entries(entries)
225 def get_option_group(self, parser=None):
226 """ Returns the corresponding GOptionGroup object.
228 Can be used as parameter for gnome_program_init(), gtk_init().
230 self.set_values_to_defaults()
231 return self._to_goptiongroup(parser)
233 def set_values_to_defaults(self):
234 for option in self.option_list:
235 default = self.defaults.get(option.dest)
236 if isinstance(default, _basestring):
237 opt_str = option.get_opt_string()
238 self.defaults[option.dest] = option.check_value(
240 self.values = optparse.Values(self.defaults)
243 class OptionParser(optparse.OptionParser):
244 """Command line parser with GOption support.
246 :param bool help_enabled:
247 The --help, --help-all and --help-{group} options are enabled (default).
248 :param bool ignore_unknown_options:
249 Do not throw a exception when a option is not knwon, the option
250 will be in the result list.
253 The OptionParser interface is not the exactly the same as the
254 optparse.OptionParser interface. Especially the usage parameter
255 is only used to show the metavar of the arguements.
257 OptionParser.add_option_group() does not only accept OptionGroup instances
258 but also glib.OptionGroup, which is returned by gtk_get_option_group().
260 Only glib.option.OptionGroup and glib.option.Option instances should
261 be passed as groups and options.
263 For further help, see optparse.OptionParser.
266 def __init__(self, *args, **kwargs):
267 if 'option_class' not in kwargs:
268 kwargs['option_class'] = Option
269 self.help_enabled = kwargs.pop('help_enabled', True)
270 self.ignore_unknown_options = kwargs.pop('ignore_unknown_options',
272 optparse.OptionParser.__init__(self, add_help_option=False,
275 def set_usage(self, usage):
278 elif usage.startswith("%prog"):
279 self.usage = usage[len("%prog"):]
283 def _to_goptioncontext(self, values):
285 parameter_string = self.usage + " - " + self.description
287 parameter_string = self.usage
288 context = _glib.OptionContext(parameter_string)
289 context.set_help_enabled(self.help_enabled)
290 context.set_ignore_unknown_options(self.ignore_unknown_options)
292 for option_group in self.option_groups:
293 if isinstance(option_group, _glib.OptionGroup):
294 g_group = option_group
296 g_group = option_group.get_option_group(self)
297 context.add_group(g_group)
299 def callback(option_name, option_value, group):
300 if option_name.startswith('--'):
301 opt = self._long_opt[option_name]
303 opt = self._short_opt[option_name]
304 opt.process(option_name, option_value, values, self)
306 main_group = _glib.OptionGroup(None, None, None, callback)
308 for option in self.option_list:
309 main_entries.extend(option._to_goptionentries())
310 main_group.add_entries(main_entries)
311 context.set_main_group(main_group)
315 def add_option_group(self, *args, **kwargs):
316 if isinstance(args[0], _basestring):
317 optparse.OptionParser.add_option_group(self,
318 OptionGroup(self, *args, **kwargs))
320 elif len(args) == 1 and not kwargs:
321 if isinstance(args[0], OptionGroup):
322 if not args[0].parser:
323 args[0].parser = self
324 if args[0].parser is not self:
325 raise ValueError("invalid OptionGroup (wrong parser)")
326 if isinstance(args[0], _glib.OptionGroup):
327 self.option_groups.append(args[0])
329 optparse.OptionParser.add_option_group(self, *args, **kwargs)
331 def _get_all_options(self):
332 options = self.option_list[:]
333 for group in self.option_groups:
334 if isinstance(group, optparse.OptionGroup):
335 options.extend(group.option_list)
338 def _process_args(self, largs, rargs, values):
339 context = self._to_goptioncontext(values)
341 # _process_args() returns the remaining parameters in rargs.
342 # The prepended program name is used to all g_set_prgname()
343 # The program name is cut away so it doesn't appear in the result.
344 rargs[:] = context.parse([sys.argv[0]] + rargs)[1:]
346 def parse_args(self, args=None, values=None):
347 old_args = args or []
349 options, args = optparse.OptionParser.parse_args(
352 error = sys.exc_info()[1]
353 if error.domain != OPTION_CONTEXT_ERROR_QUARK:
355 if error.code == GLib.OptionError.BAD_VALUE:
356 raise OptionValueError(error.message)
357 elif error.code == GLib.OptionError.UNKNOWN_OPTION:
358 raise BadOptionError(error.message)
359 elif error.code == GLib.OptionError.FAILED:
360 raise OptParseError(error.message)
364 for group in self.option_groups:
365 for key, value in group.values.__dict__.items():
366 options.ensure_value(key, value)
368 args = args[2:-len(old_args)]