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, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 """GOption command line parser
24 Extends optparse to use the GOptionGroup, GOptionEntry and GOptionContext
25 objects. So it is possible to use the gtk, gnome_program and gstreamer command
26 line groups and contexts.
28 Use this interface instead of the raw wrappers of GOptionContext and
34 from optparse import OptParseError, OptionError, OptionValueError, \
35 BadOptionError, OptionConflictError
36 from ..module import get_introspection_module
38 if sys.version_info >= (3, 0):
40 _bytes = lambda s: s.encode()
42 _basestring = basestring
45 from gi._glib import _glib
46 GLib = get_introspection_module('GLib')
48 OPTION_CONTEXT_ERROR_QUARK = GLib.quark_to_string(GLib.option_error_quark())
55 "OptionConflictError",
63 class Option(optparse.Option):
64 """Represents a command line option
66 To use the extended possibilities of the GOption API Option
67 (and make_option) are extended with new types and attributes.
70 filename The supplied arguments are read as filename, GOption
71 parses this type in with the GLib filename encoding.
74 optional_arg This does not need a arguement, but it can be supplied.
75 hidden The help list does not show this option
76 in_main This option apears in the main group, this should only
77 be used for backwards compatibility.
79 Use Option.REMAINING as option name to get all positional arguments.
81 NOTE: Every argument to an option is passed as utf-8 coded string, the only
82 exception are options which use the 'filename' type, its arguments
83 are passed as strings in the GLib filename encoding.
85 For further help, see optparse.Option.
87 TYPES = optparse.Option.TYPES + (
91 ATTRS = optparse.Option.ATTRS + [
97 REMAINING = '--' + GLib.OPTION_REMAINING
99 def __init__(self, *args, **kwargs):
100 optparse.Option.__init__(self, *args, **kwargs)
101 if not self._long_opts:
102 raise ValueError("%s at least one long option name.")
104 if len(self._long_opts) < len(self._short_opts):
106 "%s at least more long option names than short option names.")
109 raise ValueError("%s needs a help message.", self._long_opts[0])
111 def _set_opt_string(self, opts):
112 if self.REMAINING in opts:
113 self._long_opts.append(self.REMAINING)
114 optparse.Option._set_opt_string(self, opts)
115 if len(self._short_opts) > len(self._long_opts):
116 raise OptionError("goption.Option needs more long option names "
117 "than short option names")
119 def _to_goptionentries(self):
123 flags |= GLib.OptionFlags.HIDDEN
126 flags |= GLib.OptionFlags.IN_MAIN
128 if self.takes_value():
129 if self.optional_arg:
130 flags |= GLib.OptionFlags.OPTIONAL_ARG
132 flags |= GLib.OptionFlags.NO_ARG
134 if self.type == 'filename':
135 flags |= GLib.OptionFlags.FILENAME
137 for (long_name, short_name) in zip(self._long_opts, self._short_opts):
138 yield (long_name[2:], _bytes(short_name[1]), flags, self.help, self.metavar)
140 for long_name in self._long_opts[len(self._short_opts):]:
141 yield (long_name[2:], _bytes('\0'), flags, self.help, self.metavar)
144 class OptionGroup(optparse.OptionGroup):
145 """A group of command line options.
148 name: The groups name, used to create the
150 description: Shown as title of the groups help view
151 help_description: Shown as help to the --help-{name} option
152 option_list: The options used in this group, must be option.Option()
153 defaults: A dicitionary of default values
154 translation_domain: Sets the translation domain for gettext().
156 NOTE: This OptionGroup does not exactly map the optparse.OptionGroup
157 interface. There is no parser object to supply, but it is possible
158 to set default values and option_lists. Also the default values and
159 values are not shared with the OptionParser.
161 To pass a OptionGroup into a function which expects a GOptionGroup (e.g.
162 gnome_program_init() ). OptionGroup.get_option_group() can be used.
164 For further help, see optparse.OptionGroup.
166 def __init__(self, name, description, help_description="",
167 option_list=None, defaults=None,
168 translation_domain=None):
169 optparse.OptionContainer.__init__(self, Option, 'error', description)
172 self.help_description = help_description
174 self.defaults = defaults
178 self.translation_domain = translation_domain
181 for option in option_list:
182 self.add_option(option)
184 def _create_option_list(self):
185 self.option_list = []
186 self._create_option_mappings()
188 def _to_goptiongroup(self, parser):
189 def callback(option_name, option_value, group):
190 if option_name.startswith('--'):
191 opt = self._long_opt[option_name]
193 opt = self._short_opt[option_name]
196 opt.process(option_name, option_value, self.values, parser)
197 except OptionValueError:
198 error = sys.exc_info()[1]
199 gerror = _glib.GError(str(error))
200 gerror.domain = OPTION_CONTEXT_ERROR_QUARK
201 gerror.code = GLib.OptionError.BAD_VALUE
202 gerror.message = str(error)
205 group = _glib.OptionGroup(self.name, self.description,
206 self.help_description, callback)
207 if self.translation_domain:
208 group.set_translation_domain(self.translation_domain)
211 for option in self.option_list:
212 entries.extend(option._to_goptionentries())
214 group.add_entries(entries)
218 def get_option_group(self, parser=None):
219 """ Returns the corresponding GOptionGroup object.
221 Can be used as parameter for gnome_program_init(), gtk_init().
223 self.set_values_to_defaults()
224 return self._to_goptiongroup(parser)
226 def set_values_to_defaults(self):
227 for option in self.option_list:
228 default = self.defaults.get(option.dest)
229 if isinstance(default, _basestring):
230 opt_str = option.get_opt_string()
231 self.defaults[option.dest] = option.check_value(
233 self.values = optparse.Values(self.defaults)
236 class OptionParser(optparse.OptionParser):
237 """Command line parser with GOption support.
239 NOTE: The OptionParser interface is not the exactly the same as the
240 optparse.OptionParser interface. Especially the usage parameter
241 is only used to show the metavar of the arguements.
244 help_enabled: The --help, --help-all and --help-{group}
245 options are enabled (default).
246 ignore_unknown_options: Do not throw a exception when a option is not
247 knwon, the option will be in the result list.
249 OptionParser.add_option_group() does not only accept OptionGroup instances
250 but also glib.OptionGroup, which is returned by gtk_get_option_group().
252 Only glib.option.OptionGroup and glib.option.Option instances should
253 be passed as groups and options.
255 For further help, see optparse.OptionParser.
258 def __init__(self, *args, **kwargs):
259 if 'option_class' not in kwargs:
260 kwargs['option_class'] = Option
261 self.help_enabled = kwargs.pop('help_enabled', True)
262 self.ignore_unknown_options = kwargs.pop('ignore_unknown_options',
264 optparse.OptionParser.__init__(self, add_help_option=False,
267 def set_usage(self, usage):
270 elif usage.startswith("%prog"):
271 self.usage = usage[len("%prog"):]
275 def _to_goptioncontext(self, values):
277 parameter_string = self.usage + " - " + self.description
279 parameter_string = self.usage
280 context = _glib.OptionContext(parameter_string)
281 context.set_help_enabled(self.help_enabled)
282 context.set_ignore_unknown_options(self.ignore_unknown_options)
284 for option_group in self.option_groups:
285 if isinstance(option_group, _glib.OptionGroup):
286 g_group = option_group
288 g_group = option_group.get_option_group(self)
289 context.add_group(g_group)
291 def callback(option_name, option_value, group):
292 if option_name.startswith('--'):
293 opt = self._long_opt[option_name]
295 opt = self._short_opt[option_name]
296 opt.process(option_name, option_value, values, self)
298 main_group = _glib.OptionGroup(None, None, None, callback)
300 for option in self.option_list:
301 main_entries.extend(option._to_goptionentries())
302 main_group.add_entries(main_entries)
303 context.set_main_group(main_group)
307 def add_option_group(self, *args, **kwargs):
308 if isinstance(args[0], _basestring):
309 optparse.OptionParser.add_option_group(self,
310 OptionGroup(self, *args, **kwargs))
312 elif len(args) == 1 and not kwargs:
313 if isinstance(args[0], OptionGroup):
314 if not args[0].parser:
315 args[0].parser = self
316 if args[0].parser is not self:
317 raise ValueError("invalid OptionGroup (wrong parser)")
318 if isinstance(args[0], _glib.OptionGroup):
319 self.option_groups.append(args[0])
321 optparse.OptionParser.add_option_group(self, *args, **kwargs)
323 def _get_all_options(self):
324 options = self.option_list[:]
325 for group in self.option_groups:
326 if isinstance(group, optparse.OptionGroup):
327 options.extend(group.option_list)
330 def _process_args(self, largs, rargs, values):
331 context = self._to_goptioncontext(values)
333 # _process_args() returns the remaining parameters in rargs.
334 # The prepended program name is used to all g_set_prgname()
335 # The program name is cut away so it doesn't appear in the result.
336 rargs[:] = context.parse([sys.argv[0]] + rargs)[1:]
338 def parse_args(self, args=None, values=None):
339 old_args = args or []
341 options, args = optparse.OptionParser.parse_args(
344 error = sys.exc_info()[1]
345 if error.domain != OPTION_CONTEXT_ERROR_QUARK:
347 if error.code == GLib.OptionError.BAD_VALUE:
348 raise OptionValueError(error.message)
349 elif error.code == GLib.OptionError.UNKNOWN_OPTION:
350 raise BadOptionError(error.message)
351 elif error.code == GLib.OptionError.FAILED:
352 raise OptParseError(error.message)
356 for group in self.option_groups:
357 for key, value in group.values.__dict__.items():
358 options.ensure_value(key, value)
360 args = args[2:-len(old_args)]