More cleanups to Setting/Argument type handling, mostly for count != 1.
authorW. Trevor King <wking@drexel.edu>
Wed, 4 Aug 2010 00:01:55 +0000 (20:01 -0400)
committerW. Trevor King <wking@drexel.edu>
Wed, 4 Aug 2010 00:01:55 +0000 (20:01 -0400)
12 files changed:
hooke/config.py
hooke/driver/__init__.py
hooke/driver/hemingway.py
hooke/driver/mfp3d.py
hooke/driver/picoforce.py
hooke/driver/wtk.py
hooke/plugin/__init__.py
hooke/plugin/convfilt.py
hooke/plugin/flatfilt.py
hooke/ui/gui/__init__.py
hooke/ui/gui/panel/plot.py
hooke/util/convert.py

index 1c5c4874d53d4191078b599f8fb5aa6e91e8e380..d43a5f4206f29463b6001a4ecef13ba3ee0c1a76 100644 (file)
@@ -21,6 +21,7 @@ Hooke.
 """
 
 import ConfigParser as configparser
+import logging
 import os.path
 import textwrap
 import unittest
@@ -44,11 +45,12 @@ class Setting (object):
     """An entry (section or option) in HookeConfigParser.
     """
     def __init__(self, section, option=None, value=None, type='string',
-                 help=None, wrap=True):
+                 count=1, help=None, wrap=True):
         self.section = section
         self.option = option
-        self.value = to_string(value=value, type=type)
+        self.value = value
         self.type = type
+        self.count = count
         self.help = help
         self.wrap = wrap
 
@@ -299,13 +301,20 @@ class HookeConfigParser (configparser.RawConfigParser):
         for i,kv in enumerate(items):
             key,value = kv
             setting = self._default_settings_dict[(section, key)]
-            items[i] = (key, from_string(value=value, type=setting.type))
+            try:
+                items[i] = (key, from_string(value=value, type=setting.type,
+                                             count=setting.count))
+            except ValueError, e:
+                log = logging.getLogger('hooke') 
+                log.error("could not convert '%s' (%s) for %s/%s: %s"
+                          % (value, type(value), section, key, e))
+                raise
         return items
 
     def set(self, section, option, value):
         """Set an option."""
         setting = self._default_settings_dict[(section, option)]
-        value = to_string(value=value, type=setting.type)
+        value = to_string(value=value, type=setting.type, count=setting.count)
         # Can't use super() because RawConfigParser is a classic class
         #return super(HookeConfigParser, self).set(section, option, value)
         configparser.RawConfigParser.set(self, section, option, value)
index 0e860c18cbccbb69e220259adc823d66879f0df6..4e37d79f07e16cf804782ffd70623031e2d8d92c 100644 (file)
@@ -117,7 +117,8 @@ def default_settings():
         settings.append(Setting(
                 section=DRIVER_SETTING_SECTION,
                 option=driver.name,
-                value=str(default_include),
+                value=default_include,
+                type='bool',
                 help=help,
                 ))
     for dnode in DRIVER_GRAPH:
index 4f837c9f7f1e13b55bd6b24a2442c0d349352eb1..0c8ff36c1fa18a123adb34440f10d0f3df755abd 100644 (file)
@@ -24,7 +24,6 @@ import numpy
 
 from .. import curve as curve
 from .. import experiment as experiment
-from ..config import Setting
 from ..util.util import Closing as Closing
 from . import Driver as Driver
 
index c57643cc67fad1a206dffcbe256e54923d4f0ddd..63c1a28ed7f7f5b74e06d0d4fc19278c5218cf98 100644 (file)
@@ -37,7 +37,6 @@ import numpy
 
 from .. import curve as curve
 from .. import experiment as experiment
-from ..config import Setting
 from . import Driver as Driver
 from .igorbinarywave import loadibw
 
index 19f8e3dd2c1b62c5e7094ec202ef824227df060a..c084408aa0a51ea0eca406e1061e4c7232ba3d58 100644 (file)
@@ -29,7 +29,6 @@ import numpy
 
 from .. import curve as curve # this module defines data containers.
 from .. import experiment as experiment # this module defines expt. types
-from ..config import Setting # configurable setting class
 from . import Driver as Driver # this is the Driver base class
 
 
index 893512076eafdd6d2f144e1620d75c58be7bcd7f..363096b35a3d9959e8cc1a27eed9a4c2ea46c326 100644 (file)
@@ -69,7 +69,7 @@ class WTKDriver (Driver):
             Setting(section=self.setting_section, help=self.__doc__),
             Setting(section=self.setting_section,
                     option='cantilever calibration directory',
-                    value=calibcant_dir,
+                    value=calibcant_dir, type='path',
                     help='Set the directory where cantilever calibration data is stored'),
             ]
 
index 3d3efd9b93a48666a8cda0739d55fd199eae5881..8e77f2fd90f834c1d49fec30aaf7e471acbd5139 100644 (file)
@@ -124,11 +124,15 @@ def argument_to_setting(section_name, argument):
     """Convert an :class:`~hooke.command.Argument` to a
     `~hooke.conf.Setting`.
 
-    This is a lossy transition, because
+    This is useful if, for example, you want to define arguments with
+    configurable default values.
+
+    Conversion is lossy transition, because
     :class:`~hooke.command.Argument`\s store more information than
     `~hooke.conf.Setting`\s.
     """
     return Setting(section_name, option=argument.name, value=argument.default,
+                   type=argument.type, count=argument.count,
                    help=argument._help)
 
 
index 22b26c765d1285fb82e37501103832c4ccd40268..b8d967ae6be224b92d1252af6bd0503e0219b84d 100644 (file)
@@ -55,7 +55,7 @@ class ConvFiltPlugin (Plugin):
     def __init__(self):
         super(ConvFiltPlugin, self).__init__(name='convfilt')
         self._arguments = [ # for Command initialization
-            Argument('convolution', type='float', count='-1',
+            Argument('convolution', type='float', count=-1,
                      default=[11.0]+[-1.0]*11, help="""
 Convolution vector roughly matching post-peak cantilever rebound.
 This should roughly match the shape of the feature you're looking for.
@@ -75,7 +75,7 @@ Minimum number of peaks for curve acceptance.
                           ('max cut', 0.2),
                           ('min deviations', 5.0),
                           ('min points', 1),
-                          ('see double', 10e-9),
+                          ('see double', 10), # TODO: points vs. meters. 10e-9),
                           ]:
             argument = [a for a in self._arguments if a.name == key][0]
             argument.default = value
index 9bf6db54ec64bbb5b39a6d7fda4a7a3963e8dff7..4e77f3cc647f8dc289c69af5efa93d166bfbd7f0 100644 (file)
@@ -72,7 +72,7 @@ Minimum number of peaks for curve acceptance.
                           ('max cut', 0.2),
                           ('min deviations', 9.0),
                           ('min points', 4),
-                          ('see double', 10e-9),
+                          ('see double', 10), # TODO: points vs. meters. 10e-9),
                           ]:
             argument = [a for a in self._arguments if a.name == key][0]
             argument.default = value
index bbcbc0faae81bde0b30f4cbf3f33f95c3a535848..5eeff7da16ebc680343581d9dbd9af4b8d86941d 100644 (file)
@@ -137,7 +137,7 @@ class HookeFrame (wx.Frame):
 #                    size=(200, 250),
 #                    style=wx.DIRCTRL_SHOW_FILTERS,
 #                    filter=self.gui.config['folders-filters'],
-#                    defaultFilter=int(self.gui.config['folders-filter-index'])), 'left'),  #HACK: config should convert
+#                    defaultFilter=self.gui.config['folders-filter-index']), 'left'),
             (panel.PANELS['playlist'](
                     callbacks={
                         'delete_playlist':self._on_user_delete_playlist,
@@ -291,7 +291,7 @@ class HookeFrame (wx.Frame):
     def _file_name(self, name):
         """Cleanup names according to configured preferences.
         """
-        if self.gui.config['hide extensions'] == 'True':  # HACK: config should decode
+        if self.gui.config['hide extensions'] == True:
             name,ext = os.path.splitext(name)
         return name
 
@@ -914,10 +914,10 @@ class HookeApp (wx.App):
         self.SetVendorName('')
         self._setup_splash_screen()
 
-        height = int(self.gui.config['main height']) # HACK: config should convert
-        width = int(self.gui.config['main width'])
-        top = int(self.gui.config['main top'])
-        left = int(self.gui.config['main left'])
+        height = self.gui.config['main height']
+        width = self.gui.config['main width']
+        top = self.gui.config['main top']
+        left = self.gui.config['main left']
 
         # Sometimes, the ini file gets confused and sets 'left' and
         # 'top' to large negative numbers.  Here we catch and fix
@@ -940,10 +940,10 @@ class HookeApp (wx.App):
         return True
 
     def _setup_splash_screen(self):
-        if self.gui.config['show splash screen'] == 'True': # HACK: config should decode
+        if self.gui.config['show splash screen'] == True:
             path = self.gui.config['splash screen image']
             if os.path.isfile(path):
-                duration = int(self.gui.config['splash screen duration'])  # HACK: config should decode types
+                duration = self.gui.config['splash screen duration']
                 wx.SplashScreen(
                     bitmap=wx.Image(path).ConvertToBitmap(),
                     splashStyle=wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT,
@@ -977,15 +977,18 @@ class GUI (UserInterface):
             Setting(section=self.setting_section, help=self.__doc__),
             Setting(section=self.setting_section, option='icon image',
                     value=os.path.join('doc', 'img', 'microscope.ico'),
+                    type='file',
                     help='Path to the hooke icon image.'),
             Setting(section=self.setting_section, option='show splash screen',
-                    value=True,
+                    value=True, type='bool',
                     help='Enable/disable the splash screen'),
             Setting(section=self.setting_section, option='splash screen image',
                     value=os.path.join('doc', 'img', 'hooke.jpg'),
+                    type='file',
                     help='Path to the Hooke splash screen image.'),
-            Setting(section=self.setting_section, option='splash screen duration',
-                    value=1000,
+            Setting(section=self.setting_section,
+                    option='splash screen duration',
+                    value=1000, type='int',
                     help='Duration of the splash screen in milliseconds.'),
             Setting(section=self.setting_section, option='perspective path',
                     value=os.path.join('resources', 'gui', 'perspective'),
@@ -994,41 +997,42 @@ class GUI (UserInterface):
                     value='.txt',
                     help='Extension for perspective files.'),
             Setting(section=self.setting_section, option='hide extensions',
-                    value=False,
+                    value=False, type='bool',
                     help='Hide file extensions when displaying names.'),
             Setting(section=self.setting_section, option='plot legend',
-                    value=True,
+                    value=True, type='bool',
                     help='Enable/disable the plot legend.'),
             Setting(section=self.setting_section, option='plot SI format',
-                    value='True',
+                    value='True', type='bool',
                     help='Enable/disable SI plot axes numbering.'),
             Setting(section=self.setting_section, option='plot decimals',
-                    value=2,
+                    value=2, type='int',
                     help='Number of decimal places to show if "plot SI format" is enabled.'),
             Setting(section=self.setting_section, option='folders-workdir',
-                    value='.',
+                    value='.', type='path',
                     help='This should probably go...'),
             Setting(section=self.setting_section, option='folders-filters',
-                    value='.',
+                    value='.', type='path',
                     help='This should probably go...'),
             Setting(section=self.setting_section, option='active perspective',
                     value='Default',
                     help='Name of active perspective file (or "Default").'),
-            Setting(section=self.setting_section, option='folders-filter-index',
-                    value='0',
+            Setting(section=self.setting_section,
+                    option='folders-filter-index',
+                    value=0, type='int',
                     help='This should probably go...'),
             Setting(section=self.setting_section, option='main height',
-                    value=450,
+                    value=450, type='int',
                     help='Height of main window in pixels.'),
             Setting(section=self.setting_section, option='main width',
-                    value=800,
+                    value=800, type='int',
                     help='Width of main window in pixels.'),
             Setting(section=self.setting_section, option='main top',
-                    value=0,
+                    value=0, type='int',
                     help='Pixels from screen top to top of main window.'),
             Setting(section=self.setting_section, option='main left',
-                    value=0,
-                    help='Pixels from screen left to left of main window.'),            
+                    value=0, type='int',
+                    help='Pixels from screen left to left of main window.'),
             Setting(section=self.setting_section, option='selected command',
                     value='load playlist',
                     help='Name of the initially selected command.'),
index 7f024937130c20285e0345a2d0d88cf76f67e4a5..2eb9eab407b58102b1acbfe5e7c80c002bee578a 100644 (file)
@@ -259,8 +259,8 @@ class PlotPanel (Panel, wx.Panel):
             fontsize=12)
         axes = self._c['figure'].add_subplot(1, 1, 1)
 
-        if config['plot SI format'] == 'True':  # TODO: config should convert
-            d = int(config['plot decimals'])  # TODO: config should convert
+        if config['plot SI format'] == True:
+            d = config['plot decimals']
             x_n, x_unit = split_data_label(self._x_column)
             y_n, y_unit = split_data_label(self._y_column)
             fx = HookeFormatter(decimals=d, unit=x_unit)
index 92e6b64bbe2d2a3e911784a30ba0b24ac7974f56..44955a574791a9fd04f6d717b2daae45a6960cdc 100644 (file)
@@ -14,6 +14,7 @@ CONVERT_FROM_STRING = {
 
 ANALOGS = {
     'file': 'string',
+    'path': 'string',
     'point': 'int',
     }
 """Types that may be treated as other types.
@@ -33,21 +34,32 @@ RAW_TYPES = [
 """List of types that should not be converted.
 """
 
-def to_string(value, type):
+def to_string(value, type, count=1):
     """Convert `value` from `type` to a unicode string.
     """
     type = ANALOGS.get(type, type)
     if type in RAW_TYPES:
         return value
+    if count != 1:
+        values = [to_string(v, type) for v in value]
+        return '[%s]' % ', '.join(values)
     return unicode(value)
 
-def from_string(value, type):
+def from_string(value, type, count=1):
     """Convert `value` from a string to `type`.
     """
     type = ANALOGS.get(type, type)
     if type in RAW_TYPES:
         return value
     fn = globals()['_string_to_%s' % type]
+    if count != 1:
+        assert value.startswith('[') and value.endswith(']'), value
+        value = value[1:-1]  # strip off brackets
+        values = [from_string(v, type) for v in value.split(', ')]
+        assert count == -1 or len(values) == count, (
+            'array with %d != %d values: %s'
+            % (len(values), count, values))
+        return values
     return fn(value)
 
 def _string_to_string(value):