Пример #1
0
class Database(object):

    __instance = None

    @staticmethod
    def get_instance():
        '''
        This static method is used to get the singleton object for this class.
        '''
        if Database.__instance == None:
            Database()
        return Database.__instance

    def __init__(self):

        # gate the accress to __init__()
        if Database.__instance != None:
            raise Exception(
                "Database class is a singleton. Use get_instance() instead.")
        else:
            Database.__instance = self

        # Continue with init exactly once.
        self.logger = Logger(self, Logger.DEBUG)
        self.logger.debug("enter constructor")
        self.data_version = '1.0'
        self.database_name = 'shop-timer.db'
        self.open()
        self.logger.debug("leave constructor")

    @debugger
    def open(self):
        if not os.path.isfile(self.database_name):
            self.create_database()

        self.db = sql.connect(self.database_name)

    @debugger
    def close(self):
        self.db.commit()
        self.db.close()

    @debugger
    def create_database(self):
        c = sql.connect(self.database_name)
        db = c.cursor()
        db.execute('''create table assembly (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            number TEXT NOT NULL,
            description TEXT,
            notes TEXT,
            created REAL NOT NULL,
            modified REAL NOT NULL
        );''')
        db.execute('''create table part (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            number TEXT NOT NULL,
            description TEXT,
            notes TEXT,
            created REAL NOT NULL,
            modified REAL NOT NULL,
            assembly_ID INT NOT NULL
        );''')
        db.execute('''create table action (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            seq_number INTEGER NOT NULL,
            description TEXT,
            notes TEXT,
            created REAL NOT NULL,
            modified REAL NOT NULL,
            part_ID INT NOT NULL
        );''')
        db.execute('''create table timer (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            description TEXT,
            notes TEXT,
            created REAL NOT NULL,
            modified REAL NOT NULL,
            action_ID INT NOT NULL
        );''')
        db.execute('''create table timer_instance (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            start REAL NOT NULL,
            end REAL NOT NULL,
            total REAL NOT NULL,
            timer_ID INT NOT NULL
        );''')
        db.execute('''create table housekeeping (
            ID INTEGER PRIMARY KEY AUTOINCREMENT,
            last_timer_id INTEGER,
            data_version TEXT
        );''')
        db.execute("insert into housekeeping (data_version) values ('1.0');")
        c.commit()
        c.close()

    @debugger
    def _insert(self, table, fields, values):
        '''
        Do a SQL "insert" command. Create a row in the database.
        table = the table name as a string
        fields = [field names as strings]
        values = [values for the fields]
        The values can be any arbitrary type that can be converted to a string.
        '''
        sv = []
        for v in values:
            if type(v) == str:
                sv.append("\'%s\'" % (v))
            else:
                sv.append(str(v))

        sql = 'insert into %s (%s) values (%s);' % (table, ','.join(fields),
                                                    ','.join(sv))
        self.execute(sql)
        self.commit()

    @debugger
    def _select(self, table, fields=None, where=None):
        '''
        Do a SQL "select" command. Returns one or more rows as a database cursor.
        table = the table name as a string
        fields = [field names as strings]
        where = an optional expression presented as a string
        '''
        if fields is None:
            if not where is None:
                sql = "select * from %s where %s;" % (table, where)
            else:
                sql = "select * from %s;" % (table)
        elif type(fields) is str:
            if not where is None:
                sql = "select %s from %s where %s;" % (fields, table, where)
            else:
                sql = "select %s from %s;" % (fields, table)
        else:
            if not where is None:
                sql = "select %s from %s where %s;" % (','.join(fields), table,
                                                       where)
            else:
                sql = "select %s from %s;" % (','.join(fields), table)

        return self.execute(sql)

    @debugger
    def _update(self, table, field, value, where):
        '''
        Do a SQL "update" command. Modifies a row.
        table = the table name as a string
        field = a single field name as a string, or a list of field names
        value = the value to put in the field, or a list of values. may be any type
        where = a required expression presented as a string

        If the fields and values are not the same size of array, it will throw
        an IndexError exception.
        '''
        if type(field) is list:
            # convert a list of field, value variables
            arr = []
            for idx, item in enumerate(field):
                if type(value[idx]) is str:
                    arr.append('%s = \'%s\'' % (item, str(value[idx])))
                else:
                    arr.append('%s = %s' % (item, str(value[idx])))
            val = ','.join(arr)
            sql = "update %s set %s where %s;" % (table, val, where)

        else:
            if type(value) is str:
                val = "\'%s\'" % (value)
            else:
                val = str(value)
            sql = "update %s set %s = %s where %s;" % (table, field, val,
                                                       where)

        self.execute(sql)
        self.commit()

    @debugger
    def _delete(self, table, id):
        '''
        Do a SQL "delete" command. Delete a row from the database.
        table = the table name
        id = the row ID to delete
        '''
        sql = 'delete from %s where ID = %d;' % (table, id)
        self.execute(sql)
        self.commit()

    @debugger
    def get_columns(self, table):
        '''
        Return a list of all column names for the table specified.
        '''
        cols = self.execute('PRAGMA table_info(%s);' % (table))
        # for item in cols:
        #    print(item)
        return cols

    @debugger
    def convert_cursor(self, cursor, names):
        '''
        Returns a list of dicts where each row of data is in the dict with the
        name given in the order that it was read from the database.
        cursor = Sqlite3 database cursor
        names = list of names in the order they are expected
        '''
        ret_lst = []
        for row in cursor:
            val = {}
            for idx, item in enumerate(names):
                if not item is None:
                    val[item] = row[idx]
            ret_lst.append(val)

        return ret_lst

    @debugger
    def get_version(self):
        return self.data_version

    # Utilities
    @debugger
    def validate_type(self, var, t):
        '''
        Validate the type of the srguement. If it cannot be converted, then the program cannot continue.
        This is considered a developer error. The exceptions here only happen if the input validation
        from the GUI has failed.
        '''
        if type(var) != t:
            if t is float:
                try:
                    tmp = float(var)
                    return tmp
                except ValueError:
                    mbox.showerror(
                        "FATAL ERROR", "expected type %s but got type %s" %
                        (str(t), str(type(var))))
                    self.logger.fatal("expected type %s but got type %s" %
                                      (str(t), str(type(var))))
                except:
                    mbox.showerror("FATAL ERROR", "float type error.")
                    self.logger.fatal("float type error.")

            elif t is int:
                try:
                    tmp = int(var)
                    return tmp
                except ValueError:
                    mbox.showerror(
                        "FATAL ERROR", "expected type %s but got type %s" %
                        (str(t), str(type(var))))
                    self.logger.fatal("expected type %s but got type %s" %
                                      (str(t), str(type(var))))
                except:
                    mbox.showerror("FATAL ERROR", "int type error.")
                    self.logger.fatal("int type error.")

            elif t is bool:
                try:
                    tmp = bool(var)
                    return tmp
                except ValueError:
                    mbox.showerror(
                        "FATAL ERROR", "expected type %s but got type %s" %
                        (str(t), str(type(var))))
                    self.logger.fatal("expected type %s but got type %s" %
                                      (str(t), str(type(var))))
                except:
                    mbox.showerror("FATAL ERROR", "bool type error.")
                    self.logger.fatal("bool type error.")

            elif t is str:
                # anything can be converted to a str()
                return str(var)
            else:
                mbox.showerror(
                    "FATAL ERROR",
                    "attempt to validate an unexpected type %s as type %s." %
                    (str(type(var)), str(t)))
                self.logger.fatal(
                    "attempt to validate an unexpected type %s as type %s." %
                    (str(type(var)), str(t)))
        else:
            return var

    @debugger
    def execute(self, sql):
        self.logger.debug("SQL=%s" % (sql))
        return self.db.execute(sql)

    @debugger
    def commit(self):
        self.db.commit()
Пример #2
0
class DataStore:
    '''
    This is a simple class to facilitate communicating the data between
    the GUI and the calculator. It contains the state of the progam as
    it pertains to what the calculator needs to function. This object can
    be passed around providing a consistent way to access the data it
    contains.

    This is a singleton class. To get the instance call get_instance()
    '''
    __instance = None

    @staticmethod
    def get_instance():
        '''
        This static method is used to get the singleton object for this class.
        '''
        if DataStore.__instance == None:
            DataStore()
        return DataStore.__instance

    def __init__(self):

        # gate the accress to __init__()
        if DataStore.__instance != None:
            raise Exception("DataStore class is a singleton. Use get_instance() instead.")
        else:
            DataStore.__instance = self

        # Continue with init exactly once.
        self.logger = Logger(self, Logger.INFO)
        self.logger.debug("enter constructor")
        self.change_flag = False

        self.note_table = [
            {"note":"C0",      "frequency":16.35},   # index = 0
            {"note":"C#0/Db0", "frequency":17.32},   # index = 1
            {"note":"D0",      "frequency":18.35},   # index = 2
            {"note":"D#0/Eb0", "frequency":19.45},   # index = 3
            {"note":"E0",      "frequency":20.60},   # index = 4
            {"note":"F0",      "frequency":21.83},   # index = 5
            {"note":"F#0/Gb0", "frequency":23.12},   # index = 6
            {"note":"G0",      "frequency":24.50},   # index = 7
            {"note":"G#0/Ab0", "frequency":25.96},   # index = 8
            {"note":"A0",      "frequency":27.50},   # index = 9
            {"note":"A#0/Bb0", "frequency":29.14},   # index = 10
            {"note":"B0",      "frequency":30.87},   # index = 11
            {"note":"C1",      "frequency":32.70},   # index = 12
            {"note":"C#1/Db1", "frequency":34.65},   # index = 13
            {"note":"D1",      "frequency":36.71},   # index = 14
            {"note":"D#1/Eb1", "frequency":38.89},   # index = 15
            {"note":"E1",      "frequency":41.20},   # index = 16
            {"note":"F1",      "frequency":43.65},   # index = 17
            {"note":"F#1/Gb1", "frequency":46.25},   # index = 18
            {"note":"G1",      "frequency":49.00},   # index = 19
            {"note":"G#1/Ab1", "frequency":51.91},   # index = 20
            {"note":"A1",      "frequency":55.00},   # index = 21
            {"note":"A#1/Bb1", "frequency":58.27},   # index = 22
            {"note":"B1",      "frequency":61.74},   # index = 23
            {"note":"C2",      "frequency":65.41},   # index = 24
            {"note":"C#2/Db2", "frequency":69.30},   # index = 25
            {"note":"D2",      "frequency":73.42},   # index = 26
            {"note":"D#2/Eb2", "frequency":77.78},   # index = 27
            {"note":"E2",      "frequency":82.41},   # index = 28
            {"note":"F2",      "frequency":87.31},   # index = 29
            {"note":"F#2/Gb2", "frequency":92.50},   # index = 30
            {"note":"G2",      "frequency":98.00},   # index = 31
            {"note":"G#2/Ab2", "frequency":103.83},  # index = 32
            {"note":"A2",      "frequency":110.00},  # index = 33
            {"note":"A#2/Bb2", "frequency":116.54},  # index = 34
            {"note":"B2",      "frequency":123.47},  # index = 35
            {"note":"C3",      "frequency":130.81},  # index = 36
            {"note":"C#3/Db3", "frequency":138.59},  # index = 37
            {"note":"D3",      "frequency":146.83},  # index = 38
            {"note":"D#3/Eb3", "frequency":155.56},  # index = 39
            {"note":"E3",      "frequency":164.81},  # index = 40
            {"note":"F3",      "frequency":174.61},  # index = 41
            {"note":"F#3/Gb3", "frequency":185.00},  # index = 42
            {"note":"G3",      "frequency":196.00},  # index = 43
            {"note":"G#3/Ab3", "frequency":207.65},  # index = 44
            {"note":"A3",      "frequency":220.00},  # index = 45
            {"note":"A#3/Bb3", "frequency":233.08},  # index = 46
            {"note":"B3",      "frequency":246.94},  # index = 47
            {"note":"C4",      "frequency":261.63},  # index = 48
            {"note":"C#4/Db4", "frequency":277.18},  # index = 49
            {"note":"D4",      "frequency":293.66},  # index = 50
            {"note":"D#4/Eb4", "frequency":311.13},  # index = 51
            {"note":"E4",      "frequency":329.63},  # index = 52
            {"note":"F4",      "frequency":349.23},  # index = 53
            {"note":"F#4/Gb4", "frequency":369.99},  # index = 54
            {"note":"G4",      "frequency":392.00},  # index = 55
            {"note":"G#4/Ab4", "frequency":415.30},  # index = 56
            {"note":"A4",      "frequency":440.00},  # index = 57
            {"note":"A#4/Bb4", "frequency":466.16},  # index = 58
            {"note":"B4",      "frequency":493.88},  # index = 59
            {"note":"C5",      "frequency":523.25},  # index = 60
            {"note":"C#5/Db5", "frequency":554.37},  # index = 61
            {"note":"D5",      "frequency":587.33},  # index = 62 (Default)
            {"note":"D#5/Eb5", "frequency":622.25},  # index = 63
            {"note":"E5",      "frequency":659.25},  # index = 64
            {"note":"F5",      "frequency":698.46},  # index = 65
            {"note":"F#5/Gb5", "frequency":739.99},  # index = 66
            {"note":"G5",      "frequency":783.99},  # index = 67
            {"note":"G#5/Ab5", "frequency":830.61},  # index = 68
            {"note":"A5",      "frequency":880.00},  # index = 69
            {"note":"A#5/Bb5", "frequency":932.33},  # index = 70
            {"note":"B5",      "frequency":987.77},  # index = 71
            {"note":"C6",      "frequency":1046.50}, # index = 72
            {"note":"C#6/Db6", "frequency":1108.73}, # index = 73
            {"note":"D6",      "frequency":1174.66}, # index = 74
            {"note":"D#6/Eb6", "frequency":1244.51}, # index = 75
            {"note":"E6",      "frequency":1318.51}, # index = 76
            {"note":"F6",      "frequency":1396.91}, # index = 77
            {"note":"F#6/Gb6", "frequency":1479.98}, # index = 78
            {"note":"G6",      "frequency":1567.98}, # index = 79
            {"note":"G#6/Ab6", "frequency":1661.22}, # index = 80
            {"note":"A6",      "frequency":1760.00}, # index = 81
            {"note":"A#6/Bb6", "frequency":1864.66}, # index = 82
            {"note":"B6",      "frequency":1975.53}, # index = 83
            {"note":"C7",      "frequency":2093.00}, # index = 84
            {"note":"C#7/Db7", "frequency":2217.46}, # index = 85
            {"note":"D7",      "frequency":2349.32}, # index = 86
            {"note":"D#7/Eb7", "frequency":2489.02}, # index = 87
            {"note":"E7",      "frequency":2637.02}, # index = 88
            {"note":"F7",      "frequency":2793.83}, # index = 89
            {"note":"F#7/Gb7", "frequency":2959.96}, # index = 90
            {"note":"G7",      "frequency":3135.96}, # index = 91
            {"note":"G#7/Ab7", "frequency":3322.44}, # index = 92
            {"note":"A7",      "frequency":3520.00}, # index = 93
            {"note":"A#7/Bb7", "frequency":3729.31}, # index = 94
            {"note":"B7",      "frequency":3951.07}, # index = 95
            {"note":"C8",      "frequency":4186.01}, # index = 96
            {"note":"C#8/Db8", "frequency":4434.92}, # index = 97
            {"note":"D8",      "frequency":4698.63}, # index = 98
            {"note":"D#8/Eb8", "frequency":4978.03}, # index = 99
            {"note":"E8",      "frequency":5274.04}, # index = 100
            {"note":"F8",      "frequency":5587.65}, # index = 101
            {"note":"F#8/Gb8", "frequency":5919.91}, # index = 102
            {"note":"G8",      "frequency":6271.93}, # index = 103
            {"note":"G#8/Ab8", "frequency":6644.88}, # index = 104
            {"note":"A8",      "frequency":7040.00}, # index = 105
            {"note":"A#8/Bb8", "frequency":7458.62}, # index = 106
            {"note":"B8",      "frequency":7902.13}  # index = 107
        ]

        register_event("CHANGE_UNITS_EVENT", self.change_units)

        # default values
        self.internal_data = {}
        if not os.path.isfile('default.wis'):
            utility.make_default()
        self.load()

        self.bellNoteArray = []
        for num in range(len(self.note_table)):
                self.bellNoteArray.append("%s (%s Hz)"%(self.note_table[num]["note"], str(self.note_table[num]["frequency"])))

        self.logger.debug("leave constructor")

    @debugger
    def change_units(self):
        '''
        This function is a catch-all for values that dont get converted
        elsewhere when the units are switched.
        '''
        # 'embouchure_area': 0.0656,
        # 'emb_length': 0.175,
        # 'emb_width': 0.375,
        # 'emb_diameter': 0.0,
        # 'length': 10.5,

        # if this is true, then change mm to in, else change in to mm
        if self.internal_data['units']:
            self.internal_data['emb_length'] = utility.in_to_mm(self.internal_data['emb_length'])
            self.internal_data['emb_width'] = utility.in_to_mm(self.internal_data['emb_width'])
            self.internal_data['emb_diameter'] = utility.in_to_mm(self.internal_data['emb_diameter'])
            # Must be recalculated
            #self.internal_data['length'] = utility.in_to_mm(self.internal_data['length'])
            #self.internal_data['embouchure_area'] = utility.in_to_mm(self.internal_data['embouchure_area'])
        else:
            self.internal_data['emb_length'] = utility.mm_to_in(self.internal_data['emb_length'])
            self.internal_data['emb_width'] = utility.mm_to_in(self.internal_data['emb_width'])
            self.internal_data['emb_diameter'] = utility.mm_to_in(self.internal_data['emb_diameter'])
            #Both of these must be recalculated
            #self.internal_data['length'] = utility.mm_to_in(self.internal_data['length'])
            #self.internal_data['embouchure_area'] = utility.mm_to_in(self.internal_data['embouchure_area'])

    # file IO
    @debugger
    def load(self, fname=None):
        if fname is None:
            fname = "default.wis" # the data has not been loaded yet

        with open(fname, 'rb') as fh:
            try:
                data = pickle.load(fh)
            except Exception as e:
                mbox.showerror("ERROR", "Cannot load the whistle file \"%s\"\nException: %s"%(fname, str(e)))
            self.internal_data = data
        self.clear_change_flag()

    @debugger
    def save(self, fname=None):
        try:
            if fname is None:
                fname = self.internal_data['file_name']

            if os.path.isfile(fname):
                os.rename(fname, "%s.backup"%(fname))

            with open(fname, "wb") as fh:
                pickle.dump(self.internal_data, fh, protocol=pickle.HIGHEST_PROTOCOL)

            self.clear_change_flag()
        except Exception as e:
                mbox.showerror("ERROR", "Cannot save the whistle file \"%s\"\nException: %s"%(fname, str(e)))

    # getters and setters
    @debugger
    def get_file_name(self):
        return self.internal_data['file_name']

    @debugger
    def set_file_name(self, name):
        self.internal_data['file_name'] = self.validate_type(name, str)

    @debugger
    def get_disp_frac(self):
        return self.internal_data['disp_frac']

    @debugger
    def get_units(self):
        return self.internal_data['units']

    @debugger
    def get_title(self):
        return self.internal_data['title']

    @debugger
    def get_inside_dia(self):
        return self.internal_data['inside_dia']

    @debugger
    def get_wall_thickness(self):
        return self.internal_data['wall_thickness']

    @debugger
    def get_number_holes(self):
        return self.internal_data['number_holes']

    @debugger
    def get_bell_note_select(self):
        return self.internal_data['bell_note_select']

    @debugger
    def get_bell_freq(self):
        return self.internal_data['bell_freq']

    @debugger
    def get_embouchure_area(self):
        return self.internal_data['embouchure_area']

    @debugger
    def set_disp_frac(self, val):
        self.internal_data['disp_frac'] = self.validate_type(val, bool)

    @debugger
    def set_units(self, val):
        self.internal_data['units'] = self.validate_type(val, bool)

    @debugger
    def set_title(self, val):
        self.internal_data['title'] = self.validate_type(val, str)

    @debugger
    def set_inside_dia(self, val):
        self.internal_data['inside_dia'] = self.validate_type(val, float)

    @debugger
    def set_wall_thickness(self, val):
        self.internal_data['wall_thickness'] = self.validate_type(val, float)

    @debugger
    def set_number_holes(self, val):
        #self.logger.push_level(Logger.DEBUG)
        #self.logger.debug("setting holes to %d"%(val))
        self.internal_data['number_holes'] = self.validate_type(val, int)
        #self.logger.pop_level()

    @debugger
    def set_bell_note_select(self, val):
        self.internal_data['bell_note_select'] = self.validate_type(val, int)

    @debugger
    def set_bell_freq(self, val):
        self.internal_data['bell_freq'] = self.validate_type(val, float)
        self.internal_data['freqs'][0] = self.validate_type(val, float)

    @debugger
    def set_embouchure_area(self, val):
        self.internal_data['embouchure_area'] = self.validate_type(val, float)

    @debugger
    def get_emb_length(self):
        return self.internal_data['emb_length']

    @debugger
    def get_emb_diameter(self):
        return self.internal_data['emb_diameter']

    @debugger
    def get_emb_width(self):
        return self.internal_data['emb_width']

    @debugger
    def get_emb_type(self):
        return self.internal_data['emb_type']

    @debugger
    def set_emb_length(self, val):
        self.internal_data['emb_length'] = self.validate_type(val, float)

    @debugger
    def set_emb_width(self, val):
        self.internal_data['emb_width'] = self.validate_type(val, float)

    @debugger
    def set_emb_diameter(self, val):
        self.internal_data['emb_diameter'] = self.validate_type(val, float)

    @debugger
    def set_emb_type(self, val):
        self.internal_data['emb_type'] = self.validate_type(val, int)

    def get_ecorr(self):
        return self.internal_data['ecorr']

    def get_chim_const(self):
        return self.internal_data['chim_const']

    def set_ecorr(self, val):
        self.internal_data['ecorr'] = self.validate_type(val, float)

    def set_chim_const(self, val):
        self.internal_data['chim_const'] = self.validate_type(val, float)

    @debugger
    def get_hole_inc(self):
        if self.internal_data['units']:
            return self.internal_data['hole_mm_inc']
        else:
            return self.internal_data['hole_in_inc']

    @debugger
    def get_hole_max(self):
        if self.internal_data['units']:
            return self.internal_data['hole_mm_max']
        else:
            return self.internal_data['hole_in_max']

    @debugger
    def get_hole_min(self):
        if self.internal_data['units']:
            return self.internal_data['hole_mm_min']
        else:
            return self.internal_data['hole_in_min']

    @debugger
    def get_hole_inc_in(self):
        return self.internal_data['hole_in_inc']

    @debugger
    def get_hole_max_in(self):
        return self.internal_data['hole_in_max']

    @debugger
    def get_hole_min_in(self):
        return self.internal_data['hole_in_min']

    @debugger
    def get_hole_inc_mm(self):
        return self.internal_data['hole_mm_inc']

    @debugger
    def get_hole_max_mm(self):
        return self.internal_data['hole_mm_max']

    @debugger
    def get_hole_min_mm(self):
        return self.internal_data['hole_mm_min']

    @debugger
    def set_hole_inc(self, val):
        if self.internal_data['units']:
            self.internal_data['hole_mm_inc'] = self.validate_type(val, float)
        else:
            self.internal_data['hole_in_inc'] = self.validate_type(val, float)

    @debugger
    def set_hole_max(self, val):
        if self.internal_data['units']:
            self.internal_data['hole_mm_max'] = self.validate_type(val, float)
        else:
            self.internal_data['hole_in_max'] = self.validate_type(val, float)

    @debugger
    def set_hole_min(self, val):
        if self.internal_data['units']:
            self.internal_data['hole_mm_min'] = self.validate_type(val, float)
        else:
            self.internal_data['hole_in_min'] = self.validate_type(val, float)

    @debugger
    def set_hole_inc_in(self, val):
        self.internal_data['hole_in_inc'] = self.validate_type(val, float)

    @debugger
    def set_hole_max_in(self, val):
        self.internal_data['hole_in_max'] = self.validate_type(val, float)

    @debugger
    def set_hole_min_in(self, val):
        self.internal_data['hole_in_min'] = self.validate_type(val, float)

    @debugger
    def set_hole_inc_mm(self, val):
        self.internal_data['hole_mm_inc'] = self.validate_type(val, float)

    @debugger
    def set_hole_max_mm(self, val):
        self.internal_data['hole_mm_max'] = self.validate_type(val, float)

    @debugger
    def set_hole_min_mm(self, val):
        self.internal_data['hole_mm_min'] = self.validate_type(val, float)

    @debugger
    def get_hole_size(self, index):
        return self.internal_data['hole_sizes'][index+1]

    @debugger
    def get_hole_interval(self, index):
        return self.internal_data['intervals'][index+1]

    @debugger
    def get_hole_note(self, index):
        return self.internal_data['notes'][index+1]

    @debugger
    def get_hole_freq(self, index):
        return self.internal_data['freqs'][index+1]

    @debugger
    def get_hole_location(self, index):
        return self.internal_data['locations'][index+1]

    @debugger
    def get_end_location(self):
        return self.internal_data['locations'][0]

    @debugger
    def set_end_location(self, val):
        self.internal_data['locations'][0] = self.validate_type(val, float)

    @debugger
    def get_hole_diff(self, index):
        return self.internal_data['diffs'][index+1]

    @debugger
    def get_hole_cutoff(self, index):
        return self.internal_data['cutoffs'][index+1]

    @debugger
    def get_hole_rcutoff(self, index):
        return self.internal_data['rcutoffs'][index+1]

    @debugger
    def get_hole_xloc(self, index):
        return self.internal_data['xlocs'][index+1]

    @debugger
    def get_calc_type(self):
        return self.internal_data['calc_type']

    @debugger
    def get_vsound_in(self):
        return self.internal_data['vsound_in']

    @debugger
    def get_vsound_mm(self):
        return self.internal_data['vsound_mm']

    @debugger
    def get_vsound(self):
        if self.internal_data['units']:
            return self.internal_data['vsound_mm']
        else:
            return self.internal_data['vsound_in']

    @debugger
    def get_notes(self):
        return self.internal_data['text_notes']

    @debugger
    def get_max_delta(self):
        return self.internal_data['max_delta']

    @debugger
    def get_version(self):
        # Note that there is no set_version() this is only set at build time.
        return self.internal_data['version']

    @debugger
    def set_change_flag(self):
        self.change_flag = True

    @debugger
    def get_change_flag(self):
        return self.change_flag

    @debugger
    def get_temperature(self):
        return self.internal_data['temperature']

    # @debugger
    # def get_humidity(self):
    #     return self.internal_data['humidity']

    @debugger
    def get_length(self):
        return self.internal_data['length']


    ######################################################################

    @debugger
    def set_length(self, val):
        self.internal_data['length'] = self.validate_type(val, float)

    @debugger
    def set_temperature(self, val):
        self.internal_data['temperature'] = self.validate_type(val, float)

    # @debugger
    # def set_humidity(self, val):
    #     self.internal_data['humidity'] = self.validate_type(val, float)

    @debugger
    def clear_change_flag(self):
        self.change_flag = False

    @debugger
    def set_max_delta(self, val):
        self.internal_data['max_delta'] = self.validate_type(val, float)

    @debugger
    def set_notes(self, val):
        self.internal_data['text_notes'] = self.validate_type(val, str)

    @debugger
    def set_vsound(self, val):
        if self.internal_data['units']:
            self.internal_data['vsound_mm'] = self.validate_type(val, float)
        else:
            self.internal_data['vsound_in'] = self.validate_type(val, float)

    @debugger
    def set_vsound_in(self, val):
        self.internal_data['vsound_in'] = self.validate_type(val, float)

    @debugger
    def set_vsound_mm(self, val):
        self.internal_data['vsound_mm'] = self.validate_type(val, float)

    @debugger
    def set_calc_type(self, val):
        self.internal_data['calc_type'] = self.validate_type(val, int)

    @debugger
    def set_hole_rcutoff(self, index, val):
        self.internal_data['rcutoffs'][index+1] = self.validate_type(val, float)

    @debugger
    def set_hole_xloc(self, index, val):
        self.internal_data['xlocs'][index+1] = self.validate_type(val, float)

    @debugger
    def set_hole_size(self, index, val):
        self.internal_data['hole_sizes'][index+1] = self.validate_type(val, float)

    @debugger
    def set_hole_interval(self, index, val):
        self.internal_data['intervals'][index+1] = self.validate_type(val, int)

    @debugger
    def set_hole_note(self, index, val):
        self.internal_data['notes'][index+1] = self.validate_type(val, str)

    @debugger
    def set_hole_freq(self, index, val):
        self.internal_data['freqs'][index+1] = self.validate_type(val, float)

    @debugger
    def set_hole_location(self, index, val):
        self.internal_data['locations'][index+1] = self.validate_type(val, float)

    @debugger
    def set_hole_diff(self, index, val):
        self.internal_data['diffs'][index+1] = self.validate_type(val, float)

    @debugger
    def set_hole_cutoff(self, index, val):
        self.internal_data['cutoffs'][index+1] = self.validate_type(val, float)

    @debugger
    def clear_hole_data(self):
        for x in range(12):
            #self.set_hole_size(x, 0.0)
            #self.set_hole_note(x, '')
            #self.set_hole_freq(x, 0.0)
            self.set_hole_location(x, 0.0)
            self.set_hole_diff(x, 0.0)
            self.set_hole_cutoff(x, 0.0)
            self.set_hole_rcutoff(x, 0.0)
            self.set_hole_xloc(x, 0.0)

    # Utilities
    @debugger
    def validate_type(self, var, t):
        '''
        Validate the type of the srguement. If it cannot be converted, then the program cannot continue.
        This is considered a developer error. The exceptions here only happen if the input validation
        from the GUI has failed.
        '''
        if type(var) != t:
            if t is float:
                try:
                    tmp = float(var)
                    return tmp
                except ValueError:
                    mbox.showerror("FATAL ERROR", "expected type %s but got type %s"%(str(t), str(type(var))))
                    self.logger.fatal("expected type %s but got type %s"%(str(t), str(type(var))))
                except:
                    mbox.showerror("FATAL ERROR", "float type error.")
                    self.logger.fatal("float type error.")

            elif t is int:
                try:
                    tmp = int(var)
                    return tmp
                except ValueError:
                    mbox.showerror("FATAL ERROR", "expected type %s but got type %s"%(str(t), str(type(var))))
                    self.logger.fatal("expected type %s but got type %s"%(str(t), str(type(var))))
                except:
                    mbox.showerror("FATAL ERROR", "int type error.")
                    self.logger.fatal("int type error.")

            elif t is bool:
                try:
                    tmp = bool(var)
                    return tmp
                except ValueError:
                    mbox.showerror("FATAL ERROR", "expected type %s but got type %s"%(str(t), str(type(var))))
                    self.logger.fatal("expected type %s but got type %s"%(str(t), str(type(var))))
                except:
                    mbox.showerror("FATAL ERROR", "bool type error.")
                    self.logger.fatal("bool type error.")

            elif t is str:
                # anything can be converted to a str()
                return str(var)
            else:
                mbox.showerror("FATAL ERROR", "attempt to validate an unexpected type %s as type %s."%(str(type(var)), str(t)))
                self.logger.fatal("attempt to validate an unexpected type %s as type %s."%(str(type(var)), str(t)))
        else:
            return var

    def print_data(self):
        pprint.pprint(self.internal_data)