From eee325d14069576c405bc5e12157ff76838cd1ec Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 3 Aug 2010 20:01:55 -0400 Subject: [PATCH] More cleanups to Setting/Argument type handling, mostly for count != 1. --- hooke/config.py | 17 ++++++++++--- hooke/driver/__init__.py | 3 ++- hooke/driver/hemingway.py | 1 - hooke/driver/mfp3d.py | 1 - hooke/driver/picoforce.py | 1 - hooke/driver/wtk.py | 2 +- hooke/plugin/__init__.py | 6 ++++- hooke/plugin/convfilt.py | 4 +-- hooke/plugin/flatfilt.py | 2 +- hooke/ui/gui/__init__.py | 52 ++++++++++++++++++++------------------ hooke/ui/gui/panel/plot.py | 4 +-- hooke/util/convert.py | 16 ++++++++++-- 12 files changed, 68 insertions(+), 41 deletions(-) diff --git a/hooke/config.py b/hooke/config.py index 1c5c487..d43a5f4 100644 --- a/hooke/config.py +++ b/hooke/config.py @@ -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) diff --git a/hooke/driver/__init__.py b/hooke/driver/__init__.py index 0e860c1..4e37d79 100644 --- a/hooke/driver/__init__.py +++ b/hooke/driver/__init__.py @@ -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: diff --git a/hooke/driver/hemingway.py b/hooke/driver/hemingway.py index 4f837c9..0c8ff36 100644 --- a/hooke/driver/hemingway.py +++ b/hooke/driver/hemingway.py @@ -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 diff --git a/hooke/driver/mfp3d.py b/hooke/driver/mfp3d.py index c57643c..63c1a28 100644 --- a/hooke/driver/mfp3d.py +++ b/hooke/driver/mfp3d.py @@ -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 diff --git a/hooke/driver/picoforce.py b/hooke/driver/picoforce.py index 19f8e3d..c084408 100644 --- a/hooke/driver/picoforce.py +++ b/hooke/driver/picoforce.py @@ -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 diff --git a/hooke/driver/wtk.py b/hooke/driver/wtk.py index 8935120..363096b 100644 --- a/hooke/driver/wtk.py +++ b/hooke/driver/wtk.py @@ -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'), ] diff --git a/hooke/plugin/__init__.py b/hooke/plugin/__init__.py index 3d3efd9..8e77f2f 100644 --- a/hooke/plugin/__init__.py +++ b/hooke/plugin/__init__.py @@ -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) diff --git a/hooke/plugin/convfilt.py b/hooke/plugin/convfilt.py index 22b26c7..b8d967a 100644 --- a/hooke/plugin/convfilt.py +++ b/hooke/plugin/convfilt.py @@ -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 diff --git a/hooke/plugin/flatfilt.py b/hooke/plugin/flatfilt.py index 9bf6db5..4e77f3c 100644 --- a/hooke/plugin/flatfilt.py +++ b/hooke/plugin/flatfilt.py @@ -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 diff --git a/hooke/ui/gui/__init__.py b/hooke/ui/gui/__init__.py index bbcbc0f..5eeff7d 100644 --- a/hooke/ui/gui/__init__.py +++ b/hooke/ui/gui/__init__.py @@ -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.'), diff --git a/hooke/ui/gui/panel/plot.py b/hooke/ui/gui/panel/plot.py index 7f02493..2eb9eab 100644 --- a/hooke/ui/gui/panel/plot.py +++ b/hooke/ui/gui/panel/plot.py @@ -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) diff --git a/hooke/util/convert.py b/hooke/util/convert.py index 92e6b64..44955a5 100644 --- a/hooke/util/convert.py +++ b/hooke/util/convert.py @@ -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): -- 2.26.2