This file is indexed.

/usr/lib/python2.7/dist-packages/keymon/options.py is in key-mon 1.17-1ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
#!/usr/bin/python
#
# Copyright 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Options Class for save, restoring and getting parameters from the command line.

This provides a class which handles both saving options to disk and gathering
options from the command line.

It behaves a little like optparse in that you can get or set the attributes by
name.

It uses ConfigParser to save the variables to disk in ini format.
"""
__author__ = 'Scott Kirkwood (scott+keymon@forusers.com)'

import ConfigParser
import gettext
import logging
import optparse
import os
import sys

LOG = logging.getLogger('options')

gettext.install('key-mon', 'locale')

class OptionException(Exception):
  pass

class OptionItem(object):
  """Handles on option.
  It know both about optparse options and ConfigParser options.
  By setting opt_short, opt_long to None you won't create an optparse option.
  By setting ini_group, ini_name to None you won't create a ConfigParser option.
  """
  def __init__(self, dest, _type, default, name, help,
      opt_group=None, opt_short=None, opt_long=None,
      ini_group=None, ini_name=None):
    """Create an option
    Args:
      dest: a unique name for this variable, used internally.
      _type: The data type.
      default: The default value if none given.
      name: the translated name.
      _help: Help text to show.
      opt_group: Optional option group
      opt_short: the short name of the option
      opt_long: the long name for the option
      ini_group: optional name of the group in the ini file.
      ini_name: optional name of the name in the ini file
    """
    self._dirty = False
    self._value = None
    self._temp_value = None

    self._dest = dest
    self._type = _type
    self._default = default
    self._name = name
    self._help = help
    self._opt_group = opt_group
    self._opt_short = opt_short
    if self._opt_short and not self._opt_short.startswith('-'):
      raise OptionException('Invalid short option %s' % self._opt_short)
    self._opt_long = opt_long
    if self._opt_long and not self._opt_long.startswith('--'):
      raise OptionException('Invalid long option %r' % self._opt_long)
    self._ini_group = ini_group
    self._ini_name = ini_name
    if self._type not in ('int', 'float', 'bool', 'str'):
      raise OptionException('Unsupported type: %s' % self._type)
    self._set_value(default)

  def add_to_parser(self, parser):
    if not self._opt_short and not self._opt_long:
      return
    if self._type == 'bool':
      self._add_bool_to_parser(parser)
      return
    args = []
    if self._opt_short:
      args.append(self._opt_short)
    if self._opt_long:
      args.append(self._opt_long)
    parser.add_option(dest=self._dest, type=self._type, default=self._default,
       help=self._help, *args)

  def _add_bool_to_parser(self, parser):
    """Booleans need special handling."""
    args = []
    if self._opt_short:
      args.append(self._opt_short)
    if self._opt_long:
      args.append(self._opt_long)
    parser.add_option(action='store_true', default=self._default,
      dest=self._dest, help=self._help, *args)

    if self._ini_group:
      # Only need the --no version if it could be saved to ini file.
      parser.add_option('--no' + self._opt_long.lstrip('-'),
              action='store_false',
              dest=self._dest, help=_('Opposite of %s') % self._opt_long)

  def set_from_optparse(self, opts, args):
    """Try and set an option from optparse.
    Args:
      opts: options as returned from parse_args()
      args: arguments as returned bys sys.args.
    """
    if not self._opt_short and not self._opt_long:
      return

    # Was this option actually passed on the command line?
    found = False
    if args:
      for arg in args:
        if self._type == 'bool' and arg.startswith('--no'):
          arg = '--' + arg[4:]
        # Remove the --x=123, if any
        arg = arg.split('=')[0]
        if arg == self._opt_short or arg == self._opt_long:
          found = True
          break

    if hasattr(opts, self._dest):
      opt_val = getattr(opts, self._dest)
      if not self._ini_name:
        # For commands like --version which don't have stored values
        self._set_value(opt_val)
      if found:
        self._set_temp_value(opt_val)

  def reset_to_default(self):
    """Reset to the default value."""
    self._set_value(self._default)
    self._set_temp_value(None)

  def get_value(self):
    """Return the value."""
    if self._temp_value is not None:
      return self._temp_value
    return self._value

  def _set_attr_value(self, attr, val):
    """Set the value via attribute name.
    Args:
      attr: attribute name ('_value', or '_temp_value')
      val: value to set
    """
    old_val = getattr(self, attr)
    if val is None:
      setattr(self, attr, val)
    elif self._type == 'int':
      setattr(self, attr, int(val))
    elif self._type == 'float':
      setattr(self, attr, float(val))
    elif self._type == 'bool':
      if isinstance(val, basestring):
        if val.lower() in ('false', 'off', 'no', '0'):
          setattr(self, attr, False)
        elif val.lower() in ('true', 'on', 'yes', '1'):
          setattr(self, attr, True)
        else:
          raise OptionException('Unable to convert %s to bool' % val)
      else:
        setattr(self, attr, bool(val))
    else:
      setattr(self, attr, val)
    self._dirty = old_val != getattr(self, attr)

  def _set_value(self, val):
    self._set_attr_value('_value', val)
    self._set_attr_value('_temp_value', None)

  def _set_temp_value(self, val):
    self._set_attr_value('_temp_value', val)

  value = property(get_value, _set_value, doc="Value")

  @property
  def dest(self):
    """Destination variable name."""
    return self._dest

  @property
  def name(self):
    """Localized name of the option."""
    return self._name

  @property
  def help(self):
    """Long description of the option."""
    return self._help

  @property
  def type(self):
    """String name of the type."""
    return self._type

  @property
  def opt_group(self):
    """Option group, if any."""
    return self._opt_group

  @property
  def opt_short(self):
    """Short option property (ex. '-v')."""
    return self._opt_short

  @property
  def opt_long(self):
    """Long option property (ex. '--verbose')."""
    return self._opt_long

  @property
  def ini_group(self):
    """Name of the ini group or None."""
    return self._ini_group

  @property
  def ini_name(self):
    """Name in the ini, or None."""
    return self._ini_name

  @property
  def ini_value(self):
    """Value to store in the ini, always a string."""
    if self._value is None:
      return None
    if self._type == 'bool':
      if self._value is True:
        return '1'
      else:
        return '0'
    else:
      return str(self._value)


class Options(object):
  """Store the options in memory, also saves to dist and creates opt_parser."""
  def __init__(self):
    self._options = {}
    self._ini_filename = None
    self._opt_group = None
    self._opt_group_desc = {}
    self._options_order = []

  def __getattr__(self, name):
    if name not in self.__dict__['_options']:
      raise AttributeError('Invalid attribute name: %r' % name)
    return self._options[name].value

  def __setattr__(self, name, value):
    if name == '_options' or name not in self.__dict__['_options']:
      object.__setattr__(self, name, value)
    else:
      LOG.info('Setting %r = %r', name, value)
      self.__dict__['_options'][name].value = value

  def add_option_group(self, group, desc):
    self._opt_group = group
    self._opt_group_desc[group] = desc

  def add_option(self, dest, type='str', default=None, name=None, help=None,
      opt_short=None, opt_long=None,
      ini_group=None, ini_name=None):
    """Create an option
    Args:
      dest: a unique name for this variable, used internally.
      type: The data type.
      default: The default value if none given.
      name: the translated name.
      help: Help text to show.
      opt_group: the name of the option group or None
      opt_short: the short name of the option
      opt_long: the long name for the option
      ini_group: the name of the group in the ini file.
      ini_name: the name of the name in the ini file
    """
    if dest in self._options:
      raise OptionException('Options %s already added' % dest)

    self._options_order.append(dest)
    self._options[dest] = OptionItem(dest, type, default,
        name, help,
        opt_group=self._opt_group, opt_short=opt_short, opt_long=opt_long,
        ini_group=ini_group, ini_name=ini_name)

  def parse_args(self, desc, args=None):
    """Add the options to the optparse instance and parse command line
    Args:
      desc: Description to use for the program.
      args: Args for testing or sys.args[1:] otherwise
    """
    parser = optparse.OptionParser(desc)
    for dest in self._options_order:
      opt = self._options[dest]
      opt.add_to_parser(parser)

    self._opt_ret, self._other_args = parser.parse_args(args)
    for opt in self._options.values():
      opt.set_from_optparse(self._opt_ret, args)

  def parse_ini(self, fp):
    """Parser an ini file from fp, which is file-like class."""

    config = ConfigParser.SafeConfigParser()
    config.readfp(fp)
    checker = {}
    for opt in self._options.values():
      if opt.ini_group:
        checker[opt.ini_group + '-' + opt.ini_name] = True
        if (config.has_section(opt.ini_group) and
            config.has_option(opt.ini_group, opt.ini_name)):
          opt.value = config.get(opt.ini_group, opt.ini_name)
          LOG.info('From ini getting %s.%s = %s', opt.ini_group, opt.ini_name,
              opt.value)
    for section in config.sections():
      for name, value in config.items(section):
        combined_name = section + '-' + name
        if not combined_name in checker:
          LOG.info('Unknown option %r in section [%s]', name, section)
          # we no longer throw an error to be backward compatible

  def write_ini(self, fp):
    """Parser an ini file from fp, which is file-like class."""

    config = ConfigParser.SafeConfigParser()
    for opt in self._options.values():
      if not opt.ini_group:
        continue
      if not config.has_section(opt.ini_group):
        config.add_section(opt.ini_group)

      if opt.ini_value is not None:
        config.set(opt.ini_group, opt.ini_name, opt.ini_value)
    config.write(fp)

  def read_ini_file(self, fname):
    self._ini_filename = os.path.expanduser(fname)
    LOG.info('Reading from %r', self._ini_filename)
    if os.path.exists(self._ini_filename) and os.path.isfile(self._ini_filename):
      fi = open(self._ini_filename)
      self.parse_ini(fi)
      fi.close()
    else:
      LOG.info('%r does not exist', self._ini_filename)

  def save(self):
    self._write_ini_file(self._ini_filename)

  def _make_dirs(self, fname):
    if not os.path.exists(fname):
      dirname = os.path.dirname(fname)
      if not os.path.exists(dirname):
        LOG.info('Creating directory %r', dirname)
        os.makedirs(dirname)

  def _write_ini_file(self, fname):
    self._make_dirs(fname)
    LOG.info('Writing config file %r', fname)
    fo = open(fname, 'w')
    self.write_ini(fo)
    fo.close()

  def reset_to_defaults(self):
    """Reset ini file to defaults."""
    for opt in self._options.values():
      if not opt.ini_group:
        continue
      opt.reset_to_default()

if __name__ == '__main__':
  o = Options()
  o.add_option(opt_short='-l', opt_long='--larger', dest='larger', default=False,
               type='bool',
               help='Make the dialog 25% larger than normal.')
  o.add_option(opt_short='-m', opt_long='--meta', dest='meta', type='bool',
               ini_group='buttons', ini_name='meta', default=False,
               help='Show the meta (windows) key.')
  o.add_option(opt_long='--scale', dest='scale', type='float', default=1.0,
               ini_group='ui', ini_name='scale',
               help='Scale the dialog. ex. 2.0 is 2 times larger, 0.5 is '
                    'half the size. Defaults to %default')
  o.add_option(opt_long='--kbdfile', dest='kbd_file',
               ini_group='devices', ini_name='map',
               default='us.kbd',
               help='Use this kbd filename instead running xmodmap.')
  o.add_option(opt_short='-v', opt_long='--version', dest='version', type='bool',
               help='Show version information and exit.')
  o.add_option(opt_short='-t', opt_long='--theme', dest='theme', type='str',
               ini_group='ui', ini_name='theme',
               help='The theme to use when drawing status images (ex. "-t apple").')
  o.add_option(opt_long='--list-themes', dest='list_themes', type='bool',
               help='List available themes')
  o.add_option(opt_long='--old-keys', dest='old_keys', type='int',
               ini_group='buttons', ini_name='old-keys',
               help='How many historical keypresses to show (defaults to %default)',
               default=0)
  o.add_option(opt_short=None, opt_long=None, type='int',
               dest='x_pos', default=-1, help='Last X Position',
               ini_group='position', ini_name='x')
  o.add_option_group('Developer Options', 'Don\'t use')
  o.add_option(opt_short='-d',
               opt_long='--debug', dest='debug', type='bool',
               help='Output debugging information.')
  lines = []
  lines.append('[ui]')
  lines.append('scale = 1.0')
  lines.append('theme = classic')
  lines.append('[buttons]')
  lines.append('meta = 0')
  lines.append('old-keys = 0')
  lines.append('[devices]')
  lines.append('map = us.kbd')
  lines.append('[position]')
  lines.append('x = -1')
  import StringIO
  io = StringIO.StringIO('\n'.join(lines))
  o.parse_ini(io)
  o.parse_args('%prog [options]', sys.argv)
  io = StringIO.StringIO()
  o.write_ini(io)
  print io.getvalue()