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
37 if sys.version_info >= (3, 0):
39 _bytes = lambda s: s.encode()
41 _basestring = basestring
46 _glib = sys.modules['gi._glib._glib']
53 "OptionConflictError",
61 class Option(optparse.Option):
62 """Represents a command line option
64 To use the extended possibilities of the GOption API Option
65 (and make_option) are extended with new types and attributes.
68 filename The supplied arguments are read as filename, GOption
69 parses this type in with the GLib filename encoding.
72 optional_arg This does not need a arguement, but it can be supplied.
73 hidden The help list does not show this option
74 in_main This option apears in the main group, this should only
75 be used for backwards compatibility.
77 Use Option.REMAINING as option name to get all positional arguments.
79 NOTE: Every argument to an option is passed as utf-8 coded string, the only
80 exception are options which use the 'filename' type, its arguments
81 are passed as strings in the GLib filename encoding.
83 For further help, see optparse.Option.
85 TYPES = optparse.Option.TYPES + (
89 ATTRS = optparse.Option.ATTRS + [
95 REMAINING = '--' + _glib.OPTION_REMAINING
97 def __init__(self, *args, **kwargs):
98 optparse.Option.__init__(self, *args, **kwargs)
99 if not self._long_opts:
100 raise ValueError("%s at least one long option name.")
102 if len(self._long_opts) < len(self._short_opts):
104 "%s at least more long option names than short option names.")
107 raise ValueError("%s needs a help message.", self._long_opts[0])
109 def _set_opt_string(self, opts):
110 if self.REMAINING in opts:
111 self._long_opts.append(self.REMAINING)
112 optparse.Option._set_opt_string(self, opts)
113 if len(self._short_opts) > len(self._long_opts):
114 raise OptionError("goption.Option needs more long option names "
115 "than short option names")
117 def _to_goptionentries(self):
121 flags |= _glib.OPTION_FLAG_HIDDEN
124 flags |= _glib.OPTION_FLAG_IN_MAIN
126 if self.takes_value():
127 if self.optional_arg:
128 flags |= _glib.OPTION_FLAG_OPTIONAL_ARG
130 flags |= _glib.OPTION_FLAG_NO_ARG
132 if self.type == 'filename':
133 flags |= _glib.OPTION_FLAG_FILENAME
135 for (long_name, short_name) in zip(self._long_opts, self._short_opts):
136 yield (long_name[2:], _bytes(short_name[1]), flags, self.help, self.metavar)
138 for long_name in self._long_opts[len(self._short_opts):]:
139 yield (long_name[2:], _bytes('\0'), flags, self.help, self.metavar)
142 class OptionGroup(optparse.OptionGroup):
143 """A group of command line options.
146 name: The groups name, used to create the
148 description: Shown as title of the groups help view
149 help_description: Shown as help to the --help-{name} option
150 option_list: The options used in this group, must be option.Option()
151 defaults: A dicitionary of default values
152 translation_domain: Sets the translation domain for gettext().
154 NOTE: This OptionGroup does not exactly map the optparse.OptionGroup
155 interface. There is no parser object to supply, but it is possible
156 to set default values and option_lists. Also the default values and
157 values are not shared with the OptionParser.
159 To pass a OptionGroup into a function which expects a GOptionGroup (e.g.
160 gnome_program_init() ). OptionGroup.get_option_group() can be used.
162 For further help, see optparse.OptionGroup.
164 def __init__(self, name, description, help_description="",
165 option_list=None, defaults=None,
166 translation_domain=None):
167 optparse.OptionContainer.__init__(self, Option, 'error', description)
170 self.help_description = help_description
172 self.defaults = defaults
176 self.translation_domain = translation_domain
179 for option in option_list:
180 self.add_option(option)
182 def _create_option_list(self):
183 self.option_list = []
184 self._create_option_mappings()
186 def _to_goptiongroup(self, parser):
187 def callback(option_name, option_value, group):
188 if option_name.startswith('--'):
189 opt = self._long_opt[option_name]
191 opt = self._short_opt[option_name]
194 opt.process(option_name, option_value, self.values, parser)
195 except OptionValueError:
196 error = sys.exc_info()[1]
197 gerror = _glib.GError(str(error))
198 gerror.domain = _glib.OPTION_ERROR
199 gerror.code = _glib.OPTION_ERROR_BAD_VALUE
200 gerror.message = str(error)
203 group = _glib.OptionGroup(self.name, self.description,
204 self.help_description, callback)
205 if self.translation_domain:
206 group.set_translation_domain(self.translation_domain)
209 for option in self.option_list:
210 entries.extend(option._to_goptionentries())
212 group.add_entries(entries)
216 def get_option_group(self, parser=None):
217 """ Returns the corresponding GOptionGroup object.
219 Can be used as parameter for gnome_program_init(), gtk_init().
221 self.set_values_to_defaults()
222 return self._to_goptiongroup(parser)
224 def set_values_to_defaults(self):
225 for option in self.option_list:
226 default = self.defaults.get(option.dest)
227 if isinstance(default, _basestring):
228 opt_str = option.get_opt_string()
229 self.defaults[option.dest] = option.check_value(
231 self.values = optparse.Values(self.defaults)
234 class OptionParser(optparse.OptionParser):
235 """Command line parser with GOption support.
237 NOTE: The OptionParser interface is not the exactly the same as the
238 optparse.OptionParser interface. Especially the usage parameter
239 is only used to show the metavar of the arguements.
242 help_enabled: The --help, --help-all and --help-{group}
243 options are enabled (default).
244 ignore_unknown_options: Do not throw a exception when a option is not
245 knwon, the option will be in the result list.
247 OptionParser.add_option_group() does not only accept OptionGroup instances
248 but also glib.OptionGroup, which is returned by gtk_get_option_group().
250 Only glib.option.OptionGroup and glib.option.Option instances should
251 be passed as groups and options.
253 For further help, see optparse.OptionParser.
256 def __init__(self, *args, **kwargs):
257 if 'option_class' not in kwargs:
258 kwargs['option_class'] = Option
259 self.help_enabled = kwargs.pop('help_enabled', True)
260 self.ignore_unknown_options = kwargs.pop('ignore_unknown_options',
262 optparse.OptionParser.__init__(self, add_help_option=False,
265 def set_usage(self, usage):
268 elif usage.startswith("%prog"):
269 self.usage = usage[len("%prog"):]
273 def _to_goptioncontext(self, values):
275 parameter_string = self.usage + " - " + self.description
277 parameter_string = self.usage
278 context = _glib.OptionContext(parameter_string)
279 context.set_help_enabled(self.help_enabled)
280 context.set_ignore_unknown_options(self.ignore_unknown_options)
282 for option_group in self.option_groups:
283 if isinstance(option_group, _glib.OptionGroup):
284 g_group = option_group
286 g_group = option_group.get_option_group(self)
287 context.add_group(g_group)
289 def callback(option_name, option_value, group):
290 if option_name.startswith('--'):
291 opt = self._long_opt[option_name]
293 opt = self._short_opt[option_name]
294 opt.process(option_name, option_value, values, self)
296 main_group = _glib.OptionGroup(None, None, None, callback)
298 for option in self.option_list:
299 main_entries.extend(option._to_goptionentries())
300 main_group.add_entries(main_entries)
301 context.set_main_group(main_group)
305 def add_option_group(self, *args, **kwargs):
306 if isinstance(args[0], _basestring):
307 optparse.OptionParser.add_option_group(self,
308 OptionGroup(self, *args, **kwargs))
310 elif len(args) == 1 and not kwargs:
311 if isinstance(args[0], OptionGroup):
312 if not args[0].parser:
313 args[0].parser = self
314 if args[0].parser is not self:
315 raise ValueError("invalid OptionGroup (wrong parser)")
316 if isinstance(args[0], _glib.OptionGroup):
317 self.option_groups.append(args[0])
319 optparse.OptionParser.add_option_group(self, *args, **kwargs)
321 def _get_all_options(self):
322 options = self.option_list[:]
323 for group in self.option_groups:
324 if isinstance(group, optparse.OptionGroup):
325 options.extend(group.option_list)
328 def _process_args(self, largs, rargs, values):
329 context = self._to_goptioncontext(values)
331 # _process_args() returns the remaining parameters in rargs.
332 # The prepended program name is used to all g_set_prgname()
333 # The program name is cut away so it doesn't appear in the result.
334 rargs[:] = context.parse([sys.argv[0]] + rargs)[1:]
336 def parse_args(self, args=None, values=None):
337 old_args = args or []
339 options, args = optparse.OptionParser.parse_args(
342 error = sys.exc_info()[1]
343 if error.domain != _glib.OPTION_ERROR:
345 if error.code == _glib.OPTION_ERROR_BAD_VALUE:
346 raise OptionValueError(error.message)
347 elif error.code == _glib.OPTION_ERROR_UNKNOWN_OPTION:
348 raise BadOptionError(error.message)
349 elif error.code == _glib.OPTION_ERROR_FAILED:
350 raise OptParseError(error.message)
354 for group in self.option_groups:
355 for key, value in group.values.__dict__.items():
356 options.ensure_value(key, value)
358 args = args[2:-len(old_args)]