tests: don't test for specific device labels
[pygobject.git] / gi / _option.py
blob9babb2ac4c84b65dac0b8ea29370fff7e036565f
1 # -*- Mode: Python -*-
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
27 GOptionGroup in glib.
28 """
30 import sys
31 import optparse
32 from optparse import OptParseError, OptionError, OptionValueError, \
33 BadOptionError, OptionConflictError
34 from .module import get_introspection_module
35 from ._compat import string_types
37 from gi import _gi
38 from gi._error import GError
39 GLib = get_introspection_module('GLib')
41 OPTION_CONTEXT_ERROR_QUARK = GLib.quark_to_string(GLib.option_error_quark())
43 __all__ = [
44 "OptParseError",
45 "OptionError",
46 "OptionValueError",
47 "BadOptionError",
48 "OptionConflictError",
49 "Option",
50 "OptionGroup",
51 "OptionParser",
52 "make_option",
56 class Option(optparse.Option):
57 """Represents a command line option
59 To use the extended possibilities of the GOption API Option
60 (and make_option) are extended with new types and attributes.
62 Types:
63 filename The supplied arguments are read as filename, GOption
64 parses this type in with the GLib filename encoding.
66 :ivar optional_arg:
67 This does not need a arguement, but it can be supplied.
68 :ivar hidden:
69 The help list does not show this option
70 :ivar in_main:
71 This option apears in the main group, this should only
72 be used for backwards compatibility.
74 Use Option.REMAINING as option name to get all positional arguments.
76 .. NOTE::
77 Every argument to an option is passed as utf-8 coded string, the only
78 exception are options which use the 'filename' type, its arguments
79 are passed as strings in the GLib filename encoding.
81 For further help, see optparse.Option.
82 """
83 TYPES = optparse.Option.TYPES + (
84 'filename',
87 ATTRS = optparse.Option.ATTRS + [
88 'hidden',
89 'in_main',
90 'optional_arg',
93 REMAINING = '--' + GLib.OPTION_REMAINING
95 def __init__(self, *args, **kwargs):
96 optparse.Option.__init__(self, *args, **kwargs)
97 if not self._long_opts:
98 raise ValueError("%s at least one long option name.")
100 if len(self._long_opts) < len(self._short_opts):
101 raise ValueError(
102 "%s at least more long option names than short option names.")
104 if not self.help:
105 raise ValueError("%s needs a help message.", self._long_opts[0])
107 def _set_opt_string(self, opts):
108 if self.REMAINING in opts:
109 self._long_opts.append(self.REMAINING)
110 optparse.Option._set_opt_string(self, opts)
111 if len(self._short_opts) > len(self._long_opts):
112 raise OptionError("goption.Option needs more long option names "
113 "than short option names")
115 def _to_goptionentries(self):
116 flags = 0
118 if self.hidden:
119 flags |= GLib.OptionFlags.HIDDEN
121 if self.in_main:
122 flags |= GLib.OptionFlags.IN_MAIN
124 if self.takes_value():
125 if self.optional_arg:
126 flags |= GLib.OptionFlags.OPTIONAL_ARG
127 else:
128 flags |= GLib.OptionFlags.NO_ARG
130 if self.type == 'filename':
131 flags |= GLib.OptionFlags.FILENAME
133 for (long_name, short_name) in zip(self._long_opts, self._short_opts):
134 short_bytes = short_name[1]
135 if not isinstance(short_bytes, bytes):
136 short_bytes = short_bytes.encode("utf-8")
137 yield (long_name[2:], short_bytes, flags, self.help, self.metavar)
139 for long_name in self._long_opts[len(self._short_opts):]:
140 yield (long_name[2:], b'\0', flags, self.help, self.metavar)
143 class OptionGroup(optparse.OptionGroup):
144 """A group of command line options.
146 :param str name:
147 The groups name, used to create the --help-{name} option
148 :param str description:
149 Shown as title of the groups help view
150 :param str help_description:
151 Shown as help to the --help-{name} option
152 :param list option_list:
153 The options used in this group, must be option.Option()
154 :param dict defaults:
155 A dicitionary of default values
156 :param translation_domain:
157 Sets the translation domain for gettext().
159 .. NOTE::
160 This OptionGroup does not exactly map the optparse.OptionGroup
161 interface. There is no parser object to supply, but it is possible
162 to set default values and option_lists. Also the default values and
163 values are not shared with the OptionParser.
165 To pass a OptionGroup into a function which expects a GOptionGroup (e.g.
166 gnome_program_init() ). OptionGroup.get_option_group() can be used.
168 For further help, see optparse.OptionGroup.
170 def __init__(self, name, description, help_description="",
171 option_list=None, defaults=None,
172 translation_domain=None):
173 optparse.OptionContainer.__init__(self, Option, 'error', description)
174 self.name = name
175 self.parser = None
176 self.help_description = help_description
177 if defaults:
178 self.defaults = defaults
180 self.values = None
182 self.translation_domain = translation_domain
184 if option_list:
185 for option in option_list:
186 self.add_option(option)
188 def _create_option_list(self):
189 self.option_list = []
190 self._create_option_mappings()
192 def _to_goptiongroup(self, parser):
193 def callback(option_name, option_value, group):
194 if option_name.startswith('--'):
195 opt = self._long_opt[option_name]
196 else:
197 opt = self._short_opt[option_name]
199 try:
200 opt.process(option_name, option_value, self.values, parser)
201 except OptionValueError:
202 error = sys.exc_info()[1]
203 gerror = GError(str(error))
204 gerror.domain = OPTION_CONTEXT_ERROR_QUARK
205 gerror.code = GLib.OptionError.BAD_VALUE
206 gerror.message = str(error)
207 raise gerror
209 group = _gi.OptionGroup(self.name, self.description,
210 self.help_description, callback)
211 if self.translation_domain:
212 group.set_translation_domain(self.translation_domain)
214 entries = []
215 for option in self.option_list:
216 entries.extend(option._to_goptionentries())
218 group.add_entries(entries)
220 return group
222 def get_option_group(self, parser=None):
223 """ Returns the corresponding GOptionGroup object.
225 Can be used as parameter for gnome_program_init(), gtk_init().
227 self.set_values_to_defaults()
228 return self._to_goptiongroup(parser)
230 def set_values_to_defaults(self):
231 for option in self.option_list:
232 default = self.defaults.get(option.dest)
233 if isinstance(default, string_types):
234 opt_str = option.get_opt_string()
235 self.defaults[option.dest] = option.check_value(
236 opt_str, default)
237 self.values = optparse.Values(self.defaults)
240 class OptionParser(optparse.OptionParser):
241 """Command line parser with GOption support.
243 :param bool help_enabled:
244 The --help, --help-all and --help-{group} options are enabled (default).
245 :param bool ignore_unknown_options:
246 Do not throw a exception when a option is not knwon, the option
247 will be in the result list.
249 .. NOTE::
250 The OptionParser interface is not the exactly the same as the
251 optparse.OptionParser interface. Especially the usage parameter
252 is only used to show the metavar of the arguements.
254 OptionParser.add_option_group() does not only accept OptionGroup instances
255 but also glib.OptionGroup, which is returned by gtk_get_option_group().
257 Only glib.option.OptionGroup and glib.option.Option instances should
258 be passed as groups and options.
260 For further help, see optparse.OptionParser.
263 def __init__(self, *args, **kwargs):
264 if 'option_class' not in kwargs:
265 kwargs['option_class'] = Option
266 self.help_enabled = kwargs.pop('help_enabled', True)
267 self.ignore_unknown_options = kwargs.pop('ignore_unknown_options',
268 False)
269 optparse.OptionParser.__init__(self, add_help_option=False,
270 *args, **kwargs)
272 def set_usage(self, usage):
273 if usage is None:
274 self.usage = ''
275 elif usage.startswith("%prog"):
276 self.usage = usage[len("%prog"):]
277 else:
278 self.usage = usage
280 def _to_goptioncontext(self, values):
281 if self.description:
282 parameter_string = self.usage + " - " + self.description
283 else:
284 parameter_string = self.usage
285 context = _gi.OptionContext(parameter_string)
286 context.set_help_enabled(self.help_enabled)
287 context.set_ignore_unknown_options(self.ignore_unknown_options)
289 for option_group in self.option_groups:
290 if isinstance(option_group, _gi.OptionGroup):
291 g_group = option_group
292 else:
293 g_group = option_group.get_option_group(self)
294 context.add_group(g_group)
296 def callback(option_name, option_value, group):
297 if option_name.startswith('--'):
298 opt = self._long_opt[option_name]
299 else:
300 opt = self._short_opt[option_name]
301 opt.process(option_name, option_value, values, self)
303 main_group = _gi.OptionGroup(None, None, None, callback)
304 main_entries = []
305 for option in self.option_list:
306 main_entries.extend(option._to_goptionentries())
307 main_group.add_entries(main_entries)
308 context.set_main_group(main_group)
310 return context
312 def add_option_group(self, *args, **kwargs):
313 if isinstance(args[0], string_types):
314 optparse.OptionParser.add_option_group(self,
315 OptionGroup(self, *args, **kwargs))
316 return
317 elif len(args) == 1 and not kwargs:
318 if isinstance(args[0], OptionGroup):
319 if not args[0].parser:
320 args[0].parser = self
321 if args[0].parser is not self:
322 raise ValueError("invalid OptionGroup (wrong parser)")
323 if isinstance(args[0], _gi.OptionGroup):
324 self.option_groups.append(args[0])
325 return
326 optparse.OptionParser.add_option_group(self, *args, **kwargs)
328 def _get_all_options(self):
329 options = self.option_list[:]
330 for group in self.option_groups:
331 if isinstance(group, optparse.OptionGroup):
332 options.extend(group.option_list)
333 return options
335 def _process_args(self, largs, rargs, values):
336 context = self._to_goptioncontext(values)
338 # _process_args() returns the remaining parameters in rargs.
339 # The prepended program name is used to all g_set_prgname()
340 # The program name is cut away so it doesn't appear in the result.
341 rargs[:] = context.parse([sys.argv[0]] + rargs)[1:]
343 def parse_args(self, args=None, values=None):
344 try:
345 options, args = optparse.OptionParser.parse_args(
346 self, args, values)
347 except GError:
348 error = sys.exc_info()[1]
349 if error.domain != OPTION_CONTEXT_ERROR_QUARK:
350 raise
351 if error.code == GLib.OptionError.BAD_VALUE:
352 raise OptionValueError(error.message)
353 elif error.code == GLib.OptionError.UNKNOWN_OPTION:
354 raise BadOptionError(error.message)
355 elif error.code == GLib.OptionError.FAILED:
356 raise OptParseError(error.message)
357 else:
358 raise
360 for group in self.option_groups:
361 for key, value in group.values.__dict__.items():
362 options.ensure_value(key, value)
364 return options, args
367 make_option = Option