Package mvpa :: Package misc :: Module cmdline

[hide private]
[frames] | no frames]

# Source Code for Module mvpa.misc.cmdline

      1  # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
      2  # vi: set ft=python sts=4 ts=4 sw=4 et:
      3  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
      4  #
      5  #   See COPYING file distributed along with the PyMVPA package for the
      6  #   copyright and license terms.
      7  #
      8  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
      9  """Common functions and options definitions for command line
     10
     11  __docformat__ = 'restructuredtext'
     12
     13  Conventions:
     14  Every option (instance of optparse.Option) has prefix "opt". Lists of options
     15  has prefix opts (e.g. `opts.common`).
     16
     17  Option name should be camelbacked version of .dest for the option.
     18  """
     19
     20  import mvpa
     21
     22  # TODO? all options (opt*) might migrate to respective module? discuss
     23  from optparse import OptionParser, Option, OptionGroup, OptionConflictError
     24
     25  # needed for verboseCallback
     26  from mvpa.base import verbose, externals
     27
     28  # we need to make copies of the options if we place them into the
     29  # groups, since otherwise it is impossible to use them without using
     30  # the whole group. May be we should make some late creation of the
     31  # groups -- ie only if user requests a group, options are added to it.
     32  from mvpa.support import copy
     33
     34 -class Options(object):
     35      """Just a convinience placeholder for all available options
     36      """
     37      pass
     38
     39 -class OptionGroups(object):
     40      """Group creation is delayed until instance is requested.
     41
     42      This allows to overcome the problem of poluting handled cmdline options
     43      """
     44
     45 -    def __init__(self, parser):
     46          self._d = {}
     47          self._parser = parser
     48
     49 -    def add(self, name, l, doc):
     50          self._d[name] = (doc, l)
     51
     52 -    def _getGroup(self, name):
     53          try:
     54              doc, l = self._d[name]
     55          except KeyError:
     56              raise ValueError, "No group with name %s" % name
     57          opts = OptionGroup(self._parser, doc)
     58          #opts.add_options(copy.deepcopy(l)) # may be copy?
     59          try:
     60              opts.add_options(l)
     61          except OptionConflictError:
     62              print "Problem addition options to the group '%s'. Most probably" \
     63                    " the option was independently added already." % name
     64              raise
     65          return opts
     66
     67 -    def __getattribute__(self, index):
     68          if index[0] == '_':
     69              return object.__getattribute__(self, index)
     70          if self._d.has_key(index):
     71              return self._getGroup(index)
     72          return object.__getattribute__(self, index)
     73
     74
     75  # TODO: try to make groups definition somewhat lazy, since now
     76  # whenever a group is created, those parameters are already known by
     77  # parser, although might not be listed in the list of used and not by
     78  # --help. But their specification on cmdline doesn't lead to
     79  # error/help msg.
     80  #
     81  # Conflict hanlder to resolve situation that we have the same option added
     82  # to some group and also available 'freely'
     83  #
     84  # set default version string, otherwise '--version' option is not enabled
     85  # can be overwritten later on by assigning to `parser.version`
     86  parser = OptionParser(version="%prog",
     87                        add_help_option=False,
     88                        conflict_handler="error")
     89
     90
     91  opt = Options()
     92  opts = OptionGroups(parser)
     93
     94  #
     95  # Verbosity options
     96  #
     97 -def _verboseCallback(option, optstr, value, parser):
     98      """Callback for -v|--verbose cmdline option
     99      """
    100      if __debug__:
    101          debug("CMDLINE", "Setting verbose.level to %s" % str(value))
    102      verbose.level = value
    103      optstr = optstr                     # pylint shut up
    104      setattr(parser.values, option.dest, value)
    105
    106  opt.help = \
    107      Option("-h", "--help", "--sos",
    108             action="help",
    109             help="Show this help message and exit")
    110
    111  opt.verbose = \
    112      Option("-v", "--verbose", "--verbosity",
    113             action="callback", callback=_verboseCallback, nargs=1,
    114             type="int", dest="verbose", default=0,
    115             help="Verbosity level of output")
    116  """Pre-cooked `optparse`'s option to specify verbose level"""
    117
    118  commonopts_list = [opt.verbose, opt.help]
    119
    120  if __debug__:
    121      from mvpa.base import debug
    122
    123 -    def _debugCallback(option, optstr, value, parser):
    124          """Callback for -d|--debug cmdline option
    125          """
    126          if value == "list":
    127              print "Registered debug IDs:"
    128              keys = debug.registered.keys()
    129              keys.sort()
    130              for k in keys:
    131                  print "%-7s: %s" % (k, debug.registered[k])
    132              print "Use ALL: to enable all of the debug IDs listed above."
    133              print "Use python regular expressions to select group. CLF.* will" \
    134                " enable all debug entries starting with CLF (e.g. CLFBIN, CLFMC)"
    135              raise SystemExit, 0
    136
    137          optstr = optstr                     # pylint shut up
    138          debug.setActiveFromString(value)
    139
    140          setattr(parser.values, option.dest, value)
    141
    142
    143      optDebug = Option("-d", "--debug",
    144                        action="callback", callback=_debugCallback,
    145                        nargs=1,
    146                        type="string", dest="debug", default="",
    147                        help="Debug entries to report. " +
    148                        "Run with '-d list' to get a list of " +
    149                        "registered entries")
    150
    151      commonopts_list.append(optDebug)
    152
    153  opts.add("common", commonopts_list, "Common generic options")
    154
    155  #
    156  # Classifiers options
    157  #
    158  opt.clf = \
    159      Option("--clf",
    160             type="choice", dest="clf",
    161             choices=['knn', 'svm', 'ridge', 'gpr', 'smlr'], default='svm',
    162             help="Type of classifier to be used. Default: svm")
    163
    164  opt.radius = \
    165      Option("-r", "--radius",
    166             action="store", type="float", dest="radius",
    167             default=5.0,
    168             help="Radius to be used (eg for the searchlight). Default: 5.0")
    169
    170
    171  opt.knearestdegree = \
    172      Option("-k", "--k-nearest",
    173             action="store", type="int", dest="knearestdegree", default=3,
    174             help="Degree of k-nearest classifier. Default: 3")
    175
    176  opts.add('KNN', [opt.radius, opt.knearestdegree], "Specification of kNN")
    177
    178
    179  opt.svm_C = \
    180      Option("-C", "--svm-C",
    181             action="store", type="float", dest="svm_C", default=1.0,
    182             help="C parameter for soft-margin C-SVM classification. " \
    183                  "Default: 1.0")
    184
    185  opt.svm_nu = \
    186      Option("--nu", "--svm-nu",
    187             action="store", type="float", dest="svm_nu", default=0.1,
    188             help="nu parameter for soft-margin nu-SVM classification. " \
    189                  "Default: 0.1")
    190
    191  opt.svm_gamma = \
    192      Option("--gamma", "--svm-gamma",
    193             action="store", type="float", dest="svm_gamma", default=1.0,
    194             help="gamma parameter for Gaussian kernel of RBF SVM. " \
    195                  "Default: 1.0")
    196
    197  opts.add('SVM', [opt.svm_nu, opt.svm_C, opt.svm_gamma], "SVM specification")
    198
    199  opt.do_sweep = \
    200               Option("--sweep",
    201                      action="store_true", dest="do_sweep",
    202                      default=False,
    203                      help="Sweep through various classifiers")
    204
    205  # Crossvalidation options
    206
    207  opt.crossfolddegree = \
    208      Option("-c", "--crossfold",
    209             action="store", type="int", dest="crossfolddegree", default=1,
    210             help="Degree of N-fold crossfold. Default: 1")
    211
    212  opts.add('general', [opt.crossfolddegree], "Generalization estimates")
    213
    214
    215  # preprocess options
    216
    217  opt.zscore = \
    218      Option("--zscore",
    219             action="store_true", dest="zscore", default=0,
    220             help="Enable zscoring of dataset samples. Default: Off")
    221
    222  opt.tr = \
    223      Option("--tr",
    224             action="store", dest="tr", default=2.0, type='float',
    225             help="fMRI volume repetition time. Default: 2.0")
    226
    227  opt.detrend = \
    228      Option("--detrend",
    229             action="store_true", dest="detrend", default=0,
    230             help="Do linear detrending. Default: Off")
    231
    232  opts.add('preproc', [opt.zscore, opt.tr, opt.detrend], "Preprocessing options")
    233
    234
    235  # Wavelets options
    236  if externals.exists('pywt'):
    237      import pywt
    238 -    def _waveletFamilyCallback(option, optstr, value, parser):
    239          """Callback for -w|--wavelet-family cmdline option
    240          """
    241          wl_list = pywt.wavelist()
    242          wl_list_str = ", ".join(
    243                  ['-1: None'] + ['%d:%s' % w for w in enumerate(wl_list)])
    244          if value == "list":
    245              print "Available wavelet families: " + wl_list_str
    246              raise SystemExit, 0
    247
    248          wl_family = value
    249          try:
    250              # may be int? ;-)
    251              wl_family_index = int(value)
    252              if wl_family_index >= 0:
    253                  try:
    254                      wl_family = wl_list[wl_family_index]
    255                  except IndexError:
    256                      print "Index is out of range. " + \
    257                            "Following indexes with names are known: " + \
    258                            wl_list_str
    259                      raise SystemExit, -1
    260              else:
    261                  wl_family = 'None'
    262          except ValueError:
    263              pass
    264          # Check the value
    265          wl_family = wl_family.lower()
    266          if wl_family == 'none':
    267              wl_family = None
    268          elif not wl_family in wl_list:
    269              print "Uknown family '%s'. Known are %s" % (wl_family, ', '.join(wl_list))
    270              raise SystemExit, -1
    271          # Store it in the parser
    272          setattr(parser.values, option.dest, wl_family)
    273
    274
    275      opt.wavelet_family = \
    276              Option("-w", "--wavelet-family", callback=_waveletFamilyCallback,
    277                     action="callback", type="string", dest="wavelet_family",
    278                     default='-1',
    279                     help="Wavelet family: string or index among the available. " +
    280                     "Run with '-w list' to see available families")
    281
    282      opt.wavelet_decomposition = \
    283              Option("-W", "--wavelet-decomposition",
    284                     action="store", type="choice", dest="wavelet_decomposition",
    285                     default='dwt', choices=['dwt', 'dwp'],
    286                     help="Wavelet decomposition: discrete wavelet transform "+
    287                     "(dwt) or packet (dwp)")
    288
    289      opts.add('wavelet', [opt.wavelet_family, opt.wavelet_decomposition],
    290               "Wavelets mappers")
    291
    292
    293  # Box options
    294
    295  opt.boxlength = \
    296      Option("--boxlength",
    297             action="store", dest="boxlength", default=1, type='int',
    298             help="Length of the box in volumes (integer). Default: 1")
    299
    300  opt.boxoffset = \
    301      Option("--boxoffset",
    302             action="store", dest="boxoffset", default=0, type='int',
    303             help="Offset of the box from the event onset in volumes. Default: 0")
    304
    305  opts.add('box', [opt.boxlength, opt.boxoffset], "Box options")
    306
    307
    308  # sample attributes
    309
    310  opt.chunk = \
    311      Option("--chunk",
    312             action="store", dest="chunk", default='0',
    313             help="Id of the data chunk. Default: 0")
    314
    315  opt.chunkLimits = \
    316      Option("--chunklimits",
    317             action="store", dest="chunklimits", default=None,
    318             help="Limit processing to a certain chunk of data given by start " \
    319                  "and end volume number (including lower, excluding upper " \
    320                  "limit). Numbering starts with zero.")
    321
    322  opts.add('chunk', [opt.chunk, opt.chunkLimits], "Chunk options AKA Sample attributes XXX")
    323