db.py revision 1049
11049Sbinkertn@umich.eduimport MySQLdb, re, string
21049Sbinkertn@umich.edu
31049Sbinkertn@umich.edudef statcmp(a, b):
41049Sbinkertn@umich.edu    v1 = a.split('.')
51049Sbinkertn@umich.edu    v2 = b.split('.')
61049Sbinkertn@umich.edu
71049Sbinkertn@umich.edu    last = min(len(v1), len(v2)) - 1
81049Sbinkertn@umich.edu    for i,j in zip(v1[0:last], v2[0:last]):
91049Sbinkertn@umich.edu        if i != j:
101049Sbinkertn@umich.edu            return cmp(i, j)
111049Sbinkertn@umich.edu
121049Sbinkertn@umich.edu    # Special compare for last element.
131049Sbinkertn@umich.edu    if len(v1) == len(v2):
141049Sbinkertn@umich.edu        return cmp(v1[last], v2[last])
151049Sbinkertn@umich.edu    else:
161049Sbinkertn@umich.edu        return cmp(len(v1), len(v2))
171049Sbinkertn@umich.edu
181049Sbinkertn@umich.educlass RunData:
191049Sbinkertn@umich.edu    def __init__(self, row):
201049Sbinkertn@umich.edu        self.run = int(row[0])
211049Sbinkertn@umich.edu        self.name = row[1]
221049Sbinkertn@umich.edu        self.user = row[2]
231049Sbinkertn@umich.edu        self.project = row[3]
241049Sbinkertn@umich.edu
251049Sbinkertn@umich.educlass SubData:
261049Sbinkertn@umich.edu    def __init__(self, row):
271049Sbinkertn@umich.edu        self.stat = int(row[0])
281049Sbinkertn@umich.edu        self.x = int(row[1])
291049Sbinkertn@umich.edu        self.y = int(row[2])
301049Sbinkertn@umich.edu        self.name = row[3]
311049Sbinkertn@umich.edu        self.descr = row[4]
321049Sbinkertn@umich.edu
331049Sbinkertn@umich.educlass Data:
341049Sbinkertn@umich.edu    def __init__(self, row):
351049Sbinkertn@umich.edu        if len(row) != 5:
361049Sbinkertn@umich.edu            raise 'stat db error'
371049Sbinkertn@umich.edu        self.stat = int(row[0])
381049Sbinkertn@umich.edu        self.run = int(row[1])
391049Sbinkertn@umich.edu        self.x = int(row[2])
401049Sbinkertn@umich.edu        self.y = int(row[3])
411049Sbinkertn@umich.edu        self.data = float(row[4])
421049Sbinkertn@umich.edu
431049Sbinkertn@umich.edu    def __repr__(self):
441049Sbinkertn@umich.edu        return '''Data(['%d', '%d', '%d', '%d', '%f'])''' % ( self.stat,
451049Sbinkertn@umich.edu            self.run, self.x, self.y, self.data)
461049Sbinkertn@umich.edu
471049Sbinkertn@umich.educlass StatData(object):
481049Sbinkertn@umich.edu    def __init__(self, row):
491049Sbinkertn@umich.edu        self.stat = int(row[0])
501049Sbinkertn@umich.edu        self.name = row[1]
511049Sbinkertn@umich.edu        self.desc = row[2]
521049Sbinkertn@umich.edu        self.type = row[3]
531049Sbinkertn@umich.edu        self.prereq = int(row[5])
541049Sbinkertn@umich.edu        self.precision = int(row[6])
551049Sbinkertn@umich.edu
561049Sbinkertn@umich.edu        import flags
571049Sbinkertn@umich.edu        self.flags = 0
581049Sbinkertn@umich.edu        if int(row[4]): self.flags |= flags.printable
591049Sbinkertn@umich.edu        if int(row[7]): self.flags |= flags.nozero
601049Sbinkertn@umich.edu        if int(row[8]): self.flags |= flags.nonan
611049Sbinkertn@umich.edu        if int(row[9]): self.flags |= flags.total
621049Sbinkertn@umich.edu        if int(row[10]): self.flags |= flags.pdf
631049Sbinkertn@umich.edu        if int(row[11]): self.flags |= flags.cdf
641049Sbinkertn@umich.edu
651049Sbinkertn@umich.edu        if self.type == 'DIST' or self.type == 'VECTORDIST':
661049Sbinkertn@umich.edu            self.min = float(row[12])
671049Sbinkertn@umich.edu            self.max = float(row[13])
681049Sbinkertn@umich.edu            self.bktsize = float(row[14])
691049Sbinkertn@umich.edu            self.size = int(row[15])
701049Sbinkertn@umich.edu
711049Sbinkertn@umich.edu        if self.type == 'FORMULA':
721049Sbinkertn@umich.edu            self.formula = self.db.allFormulas[self.stat]
731049Sbinkertn@umich.edu
741049Sbinkertn@umich.educlass Node(object):
751049Sbinkertn@umich.edu    def __init__(self, name):
761049Sbinkertn@umich.edu        self.name = name
771049Sbinkertn@umich.edu    def __str__(self):
781049Sbinkertn@umich.edu        return name
791049Sbinkertn@umich.edu
801049Sbinkertn@umich.educlass Database(object):
811049Sbinkertn@umich.edu    def __init__(self):
821049Sbinkertn@umich.edu        self.host = 'zizzer.pool'
831049Sbinkertn@umich.edu        self.user = ''
841049Sbinkertn@umich.edu        self.passwd = ''
851049Sbinkertn@umich.edu        self.db = 'm5stats'
861049Sbinkertn@umich.edu        self.cursor = None
871049Sbinkertn@umich.edu
881049Sbinkertn@umich.edu        self.allStats = []
891049Sbinkertn@umich.edu        self.allStatIds = {}
901049Sbinkertn@umich.edu        self.allStatNames = {}
911049Sbinkertn@umich.edu
921049Sbinkertn@umich.edu        self.allSubData = {}
931049Sbinkertn@umich.edu
941049Sbinkertn@umich.edu        self.allRuns = []
951049Sbinkertn@umich.edu        self.allRunIds = {}
961049Sbinkertn@umich.edu        self.allRunNames = {}
971049Sbinkertn@umich.edu
981049Sbinkertn@umich.edu        self.allBins = []
991049Sbinkertn@umich.edu        self.allBinIds = {}
1001049Sbinkertn@umich.edu        self.allBinNames = {}
1011049Sbinkertn@umich.edu
1021049Sbinkertn@umich.edu        self.allFormulas = {}
1031049Sbinkertn@umich.edu
1041049Sbinkertn@umich.edu        self.stattop = {}
1051049Sbinkertn@umich.edu        self.statdict = {}
1061049Sbinkertn@umich.edu        self.statlist = []
1071049Sbinkertn@umich.edu
1081049Sbinkertn@umich.edu        self.mode = 'sum';
1091049Sbinkertn@umich.edu        self.runs = None
1101049Sbinkertn@umich.edu        self.bins = None
1111049Sbinkertn@umich.edu        self.ticks = None
1121049Sbinkertn@umich.edu        self.__dict__['get'] = type(self).sum
1131049Sbinkertn@umich.edu
1141049Sbinkertn@umich.edu    def query(self, sql):
1151049Sbinkertn@umich.edu        self.cursor.execute(sql)
1161049Sbinkertn@umich.edu
1171049Sbinkertn@umich.edu    def update_dict(self, dict):
1181049Sbinkertn@umich.edu        dict.update(self.stattop)
1191049Sbinkertn@umich.edu
1201049Sbinkertn@umich.edu    def append(self, stat):
1211049Sbinkertn@umich.edu        statname = re.sub(':', '__', stat.name)
1221049Sbinkertn@umich.edu        path = string.split(statname, '.')
1231049Sbinkertn@umich.edu        pathtop = path[0]
1241049Sbinkertn@umich.edu        fullname = ''
1251049Sbinkertn@umich.edu
1261049Sbinkertn@umich.edu        x = self
1271049Sbinkertn@umich.edu        while len(path) > 1:
1281049Sbinkertn@umich.edu            name = path.pop(0)
1291049Sbinkertn@umich.edu            if not x.__dict__.has_key(name):
1301049Sbinkertn@umich.edu                x.__dict__[name] = Node(fullname + name)
1311049Sbinkertn@umich.edu            x = x.__dict__[name]
1321049Sbinkertn@umich.edu            fullname = '%s%s.' % (fullname, name)
1331049Sbinkertn@umich.edu
1341049Sbinkertn@umich.edu        name = path.pop(0)
1351049Sbinkertn@umich.edu        x.__dict__[name] = stat
1361049Sbinkertn@umich.edu
1371049Sbinkertn@umich.edu        self.stattop[pathtop] = self.__dict__[pathtop]
1381049Sbinkertn@umich.edu        self.statdict[statname] = stat
1391049Sbinkertn@umich.edu        self.statlist.append(statname)
1401049Sbinkertn@umich.edu
1411049Sbinkertn@umich.edu    def connect(self):
1421049Sbinkertn@umich.edu        # connect
1431049Sbinkertn@umich.edu        self.thedb = MySQLdb.connect(db=self.db,
1441049Sbinkertn@umich.edu                                     host=self.host,
1451049Sbinkertn@umich.edu                                     user=self.user,
1461049Sbinkertn@umich.edu                                     passwd=self.passwd)
1471049Sbinkertn@umich.edu
1481049Sbinkertn@umich.edu        # create a cursor
1491049Sbinkertn@umich.edu        self.cursor = self.thedb.cursor()
1501049Sbinkertn@umich.edu
1511049Sbinkertn@umich.edu        self.query('''select rn_id,rn_name,rn_sample,rn_user,rn_project
1521049Sbinkertn@umich.edu                   from runs''')
1531049Sbinkertn@umich.edu        for result in self.cursor.fetchall():
1541049Sbinkertn@umich.edu            run = RunData(result);
1551049Sbinkertn@umich.edu            self.allRuns.append(run)
1561049Sbinkertn@umich.edu            self.allRunIds[run.run] = run
1571049Sbinkertn@umich.edu            self.allRunNames[run.name] = run
1581049Sbinkertn@umich.edu
1591049Sbinkertn@umich.edu        self.query('select * from bins')
1601049Sbinkertn@umich.edu        for id,name in self.cursor.fetchall():
1611049Sbinkertn@umich.edu            self.allBinIds[int(id)] = name
1621049Sbinkertn@umich.edu            self.allBinNames[name] = int(id)
1631049Sbinkertn@umich.edu
1641049Sbinkertn@umich.edu        self.query('select sd_stat,sd_x,sd_y,sd_name,sd_descr from subdata')
1651049Sbinkertn@umich.edu        for result in self.cursor.fetchall():
1661049Sbinkertn@umich.edu            subdata = SubData(result)
1671049Sbinkertn@umich.edu            if self.allSubData.has_key(subdata.stat):
1681049Sbinkertn@umich.edu                self.allSubData[subdata.stat].append(subdata)
1691049Sbinkertn@umich.edu            else:
1701049Sbinkertn@umich.edu                self.allSubData[subdata.stat] = [ subdata ]
1711049Sbinkertn@umich.edu
1721049Sbinkertn@umich.edu        self.query('select * from formulas')
1731049Sbinkertn@umich.edu        for id,formula in self.cursor.fetchall():
1741049Sbinkertn@umich.edu            self.allFormulas[int(id)] = formula
1751049Sbinkertn@umich.edu
1761049Sbinkertn@umich.edu        StatData.db = self
1771049Sbinkertn@umich.edu        self.query('select * from stats')
1781049Sbinkertn@umich.edu        import info
1791049Sbinkertn@umich.edu        for result in self.cursor.fetchall():
1801049Sbinkertn@umich.edu            stat = info.NewStat(StatData(result))
1811049Sbinkertn@umich.edu            self.append(stat)
1821049Sbinkertn@umich.edu            self.allStats.append(stat)
1831049Sbinkertn@umich.edu            self.allStatIds[stat.stat] = stat
1841049Sbinkertn@umich.edu            self.allStatNames[stat.name] = stat
1851049Sbinkertn@umich.edu
1861049Sbinkertn@umich.edu    # Name: listbins
1871049Sbinkertn@umich.edu    # Desc: Prints all bins matching regex argument, if no argument
1881049Sbinkertn@umich.edu    #       is given all bins are returned
1891049Sbinkertn@umich.edu    def listBins(self, regex='.*'):
1901049Sbinkertn@umich.edu        print '%-50s %-10s' % ('bin name', 'id')
1911049Sbinkertn@umich.edu        print '-' * 61
1921049Sbinkertn@umich.edu        names = self.allBinNames.keys()
1931049Sbinkertn@umich.edu        names.sort()
1941049Sbinkertn@umich.edu        for name in names:
1951049Sbinkertn@umich.edu            id = self.allBinNames[name]
1961049Sbinkertn@umich.edu            print '%-50s %-10d' % (name, id)
1971049Sbinkertn@umich.edu
1981049Sbinkertn@umich.edu    # Name: listruns
1991049Sbinkertn@umich.edu    # Desc: Prints all runs matching a given user, if no argument
2001049Sbinkertn@umich.edu    #       is given all runs are returned
2011049Sbinkertn@umich.edu    def listRuns(self, user=None):
2021049Sbinkertn@umich.edu        print '%-40s %-10s %-5s' % ('run name', 'user', 'id')
2031049Sbinkertn@umich.edu        print '-' * 62
2041049Sbinkertn@umich.edu        for run in self.allRuns:
2051049Sbinkertn@umich.edu            if user == None or user == run.user:
2061049Sbinkertn@umich.edu                print '%-40s %-10s %-10d' % (run.name, run.user, run.run)
2071049Sbinkertn@umich.edu
2081049Sbinkertn@umich.edu    # Name: listTicks
2091049Sbinkertn@umich.edu    # Desc: Prints all samples for a given run
2101049Sbinkertn@umich.edu    def listTicks(self, run=None):
2111049Sbinkertn@umich.edu        print "tick"
2121049Sbinkertn@umich.edu        print "----------------------------------------"
2131049Sbinkertn@umich.edu        sql = 'select distinct dt_tick from data where dt_stat=1950'
2141049Sbinkertn@umich.edu        #if run != None:
2151049Sbinkertn@umich.edu        #    sql += ' where dt_run=%d' % run
2161049Sbinkertn@umich.edu        self.query(sql)
2171049Sbinkertn@umich.edu        for r in self.cursor.fetchall():
2181049Sbinkertn@umich.edu            print r[0]
2191049Sbinkertn@umich.edu
2201049Sbinkertn@umich.edu    # Name: liststats
2211049Sbinkertn@umich.edu    # Desc: Prints all statistics that appear in the database,
2221049Sbinkertn@umich.edu    #         the optional argument is a regular expression that can
2231049Sbinkertn@umich.edu    #         be used to prune the result set
2241049Sbinkertn@umich.edu    def listStats(self, regex=None):
2251049Sbinkertn@umich.edu        print '%-60s %-8s %-10s' % ('stat name', 'id', 'type')
2261049Sbinkertn@umich.edu        print '-' * 80
2271049Sbinkertn@umich.edu
2281049Sbinkertn@umich.edu        rx = None
2291049Sbinkertn@umich.edu        if regex != None:
2301049Sbinkertn@umich.edu            rx = re.compile(regex)
2311049Sbinkertn@umich.edu
2321049Sbinkertn@umich.edu        stats = [ stat.name for stat in self.allStats ]
2331049Sbinkertn@umich.edu        stats.sort(statcmp)
2341049Sbinkertn@umich.edu        for stat in stats:
2351049Sbinkertn@umich.edu            stat = self.allStatNames[stat]
2361049Sbinkertn@umich.edu            if rx == None or rx.match(stat.name):
2371049Sbinkertn@umich.edu                print '%-60s %-8s %-10s' % (stat.name, stat.stat, stat.type)
2381049Sbinkertn@umich.edu
2391049Sbinkertn@umich.edu    # Name: liststats
2401049Sbinkertn@umich.edu    # Desc: Prints all statistics that appear in the database,
2411049Sbinkertn@umich.edu    #         the optional argument is a regular expression that can
2421049Sbinkertn@umich.edu    #         be used to prune the result set
2431049Sbinkertn@umich.edu    def listFormulas(self, regex=None):
2441049Sbinkertn@umich.edu        print '%-60s %s' % ('formula name', 'formula')
2451049Sbinkertn@umich.edu        print '-' * 80
2461049Sbinkertn@umich.edu
2471049Sbinkertn@umich.edu        rx = None
2481049Sbinkertn@umich.edu        if regex != None:
2491049Sbinkertn@umich.edu            rx = re.compile(regex)
2501049Sbinkertn@umich.edu
2511049Sbinkertn@umich.edu        stats = [ stat.name for stat in self.allStats ]
2521049Sbinkertn@umich.edu        stats.sort(statcmp)
2531049Sbinkertn@umich.edu        for stat in stats:
2541049Sbinkertn@umich.edu            stat = self.allStatNames[stat]
2551049Sbinkertn@umich.edu            if stat.type == 'FORMULA' and (rx == None or rx.match(stat.name)):
2561049Sbinkertn@umich.edu                print '%-60s %s' % (stat.name, self.allFormulas[stat.stat])
2571049Sbinkertn@umich.edu
2581049Sbinkertn@umich.edu    def getStat(self, stats):
2591049Sbinkertn@umich.edu        if type(stats) is not list:
2601049Sbinkertn@umich.edu            stats = [ stats ]
2611049Sbinkertn@umich.edu
2621049Sbinkertn@umich.edu        ret = []
2631049Sbinkertn@umich.edu        for stat in stats:
2641049Sbinkertn@umich.edu            if type(stat) is int:
2651049Sbinkertn@umich.edu                ret.append(self.allStatIds[stat])
2661049Sbinkertn@umich.edu
2671049Sbinkertn@umich.edu            if type(stat) is str:
2681049Sbinkertn@umich.edu                rx = re.compile(stat)
2691049Sbinkertn@umich.edu                for stat in self.allStats:
2701049Sbinkertn@umich.edu                    if rx.match(stat.name):
2711049Sbinkertn@umich.edu                        ret.append(stat)
2721049Sbinkertn@umich.edu        return ret
2731049Sbinkertn@umich.edu
2741049Sbinkertn@umich.edu    def getBin(self, bins):
2751049Sbinkertn@umich.edu        if type(bins) is not list:
2761049Sbinkertn@umich.edu            bins = [ bins ]
2771049Sbinkertn@umich.edu
2781049Sbinkertn@umich.edu        ret = []
2791049Sbinkertn@umich.edu        for bin in bins:
2801049Sbinkertn@umich.edu            if type(bin) is int:
2811049Sbinkertn@umich.edu                ret.append(bin)
2821049Sbinkertn@umich.edu            elif type(bin) is str:
2831049Sbinkertn@umich.edu                ret.append(self.allBinNames[bin])
2841049Sbinkertn@umich.edu            else:
2851049Sbinkertn@umich.edu                for name,id in self.allBinNames.items():
2861049Sbinkertn@umich.edu                    if bin.match(name):
2871049Sbinkertn@umich.edu                        ret.append(id)
2881049Sbinkertn@umich.edu
2891049Sbinkertn@umich.edu        return ret
2901049Sbinkertn@umich.edu
2911049Sbinkertn@umich.edu    def getNotBin(self, bin):
2921049Sbinkertn@umich.edu        map = {}
2931049Sbinkertn@umich.edu        for bin in getBin(bin):
2941049Sbinkertn@umich.edu            map[bin] = 1
2951049Sbinkertn@umich.edu
2961049Sbinkertn@umich.edu        ret = []
2971049Sbinkertn@umich.edu        for bin in self.allBinIds.keys():
2981049Sbinkertn@umich.edu            if not map.has_key(bin):
2991049Sbinkertn@umich.edu                ret.append(bin)
3001049Sbinkertn@umich.edu
3011049Sbinkertn@umich.edu        return ret
3021049Sbinkertn@umich.edu
3031049Sbinkertn@umich.edu    #########################################
3041049Sbinkertn@umich.edu    # get the data
3051049Sbinkertn@umich.edu    #
3061049Sbinkertn@umich.edu    def inner(self, op, stat, bins, ticks, group=False):
3071049Sbinkertn@umich.edu        sql = 'select '
3081049Sbinkertn@umich.edu        sql += 'dt_stat as stat, '
3091049Sbinkertn@umich.edu        sql += 'dt_run as run, '
3101049Sbinkertn@umich.edu        sql += 'dt_x as x, '
3111049Sbinkertn@umich.edu        sql += 'dt_y as y, '
3121049Sbinkertn@umich.edu        if group:
3131049Sbinkertn@umich.edu            sql += 'dt_tick as tick, '
3141049Sbinkertn@umich.edu        sql += '%s(dt_data) as data ' % op
3151049Sbinkertn@umich.edu        sql += 'from data '
3161049Sbinkertn@umich.edu        sql += 'where '
3171049Sbinkertn@umich.edu
3181049Sbinkertn@umich.edu        if isinstance(stat, list):
3191049Sbinkertn@umich.edu            val = ' or '.join([ 'dt_stat=%d' % s.stat for s in stat ])
3201049Sbinkertn@umich.edu            sql += ' (%s)' % val
3211049Sbinkertn@umich.edu        else:
3221049Sbinkertn@umich.edu            sql += ' dt_stat=%d' % stat.stat
3231049Sbinkertn@umich.edu
3241049Sbinkertn@umich.edu        if self.runs != None and len(self.runs):
3251049Sbinkertn@umich.edu            val = ' or '.join([ 'dt_run=%d' % r for r in self.runs ])
3261049Sbinkertn@umich.edu            sql += ' and (%s)' % val
3271049Sbinkertn@umich.edu
3281049Sbinkertn@umich.edu        if bins != None and len(bins):
3291049Sbinkertn@umich.edu            val = ' or '.join([ 'dt_bin=%d' % b for b in bins ])
3301049Sbinkertn@umich.edu            sql += ' and (%s)' % val
3311049Sbinkertn@umich.edu
3321049Sbinkertn@umich.edu        if ticks != None and len(ticks):
3331049Sbinkertn@umich.edu            val = ' or '.join([ 'dt_tick=%d' % s for s in ticks ])
3341049Sbinkertn@umich.edu            sql += ' and (%s)' % val
3351049Sbinkertn@umich.edu
3361049Sbinkertn@umich.edu        sql += ' group by dt_stat,dt_run,dt_x,dt_y'
3371049Sbinkertn@umich.edu        if group:
3381049Sbinkertn@umich.edu            sql += ',dt_tick'
3391049Sbinkertn@umich.edu        return sql
3401049Sbinkertn@umich.edu
3411049Sbinkertn@umich.edu    def outer(self, op_out, op_in, stat, bins, ticks):
3421049Sbinkertn@umich.edu        sql = self.inner(op_in, stat, bins, ticks, True)
3431049Sbinkertn@umich.edu        sql = 'select stat,run,x,y,%s(data) from (%s) as tb ' % (op_out, sql)
3441049Sbinkertn@umich.edu        sql += 'group by stat,run,x,y'
3451049Sbinkertn@umich.edu        return sql
3461049Sbinkertn@umich.edu
3471049Sbinkertn@umich.edu    # Name: sum
3481049Sbinkertn@umich.edu    # Desc: given a run, a stat and an array of samples and bins,
3491049Sbinkertn@umich.edu    #        sum all the bins and then get the standard deviation of the
3501049Sbinkertn@umich.edu    #        samples for non-binned runs. This will just return the average
3511049Sbinkertn@umich.edu    #        of samples, however a bin array still must be passed
3521049Sbinkertn@umich.edu    def sum(self, stat, bins, ticks):
3531049Sbinkertn@umich.edu        return self.inner('sum', stat, bins, ticks)
3541049Sbinkertn@umich.edu
3551049Sbinkertn@umich.edu    # Name: avg
3561049Sbinkertn@umich.edu    # Desc: given a run, a stat and an array of samples and bins,
3571049Sbinkertn@umich.edu    #        sum all the bins and then average the samples for non-binned
3581049Sbinkertn@umich.edu    #        runs this will just return the average of samples, however
3591049Sbinkertn@umich.edu    #        a bin array still must be passed
3601049Sbinkertn@umich.edu    def avg(self, stat, bins, ticks):
3611049Sbinkertn@umich.edu        return self.outer('avg', 'sum', stat, bins, ticks)
3621049Sbinkertn@umich.edu
3631049Sbinkertn@umich.edu    # Name: stdev
3641049Sbinkertn@umich.edu    # Desc: given a run, a stat and an array of samples and bins,
3651049Sbinkertn@umich.edu    #        sum all the bins and then get the standard deviation of the
3661049Sbinkertn@umich.edu    #        samples for non-binned runs. This will just return the average
3671049Sbinkertn@umich.edu    #        of samples, however a bin array still must be passed
3681049Sbinkertn@umich.edu    def stdev(self, stat, bins, ticks):
3691049Sbinkertn@umich.edu        return self.outer('stddev', 'sum', stat, bins, ticks)
3701049Sbinkertn@umich.edu
3711049Sbinkertn@umich.edu    def __getattribute__(self, attr):
3721049Sbinkertn@umich.edu        if attr != 'get':
3731049Sbinkertn@umich.edu            return super(Database, self).__getattribute__(attr)
3741049Sbinkertn@umich.edu
3751049Sbinkertn@umich.edu        if self.__dict__['get'] == type(self).sum:
3761049Sbinkertn@umich.edu            return 'sum'
3771049Sbinkertn@umich.edu        elif self.__dict__['get'] == type(self).avg:
3781049Sbinkertn@umich.edu            return 'avg'
3791049Sbinkertn@umich.edu        elif self.__dict__['get'] == type(self).stdev:
3801049Sbinkertn@umich.edu            return 'stdev'
3811049Sbinkertn@umich.edu        else:
3821049Sbinkertn@umich.edu            return ''
3831049Sbinkertn@umich.edu
3841049Sbinkertn@umich.edu    def __setattr__(self, attr, value):
3851049Sbinkertn@umich.edu        if attr != 'get':
3861049Sbinkertn@umich.edu            super(Database, self).__setattr__(attr, value)
3871049Sbinkertn@umich.edu            return
3881049Sbinkertn@umich.edu
3891049Sbinkertn@umich.edu        if value == 'sum':
3901049Sbinkertn@umich.edu            self.__dict__['get'] = type(self).sum
3911049Sbinkertn@umich.edu        elif value == 'avg':
3921049Sbinkertn@umich.edu            self.__dict__['get'] = type(self).avg
3931049Sbinkertn@umich.edu        elif value == 'stdev':
3941049Sbinkertn@umich.edu            self.__dict__['get'] = type(self).stdev
3951049Sbinkertn@umich.edu        else:
3961049Sbinkertn@umich.edu            raise AttributeError, "can only set get to: sum | avg | stdev"
3971049Sbinkertn@umich.edu
3981049Sbinkertn@umich.edu    def data(self, stat, bins=None, ticks=None):
3991049Sbinkertn@umich.edu        if bins is None:
4001049Sbinkertn@umich.edu            bins = self.bins
4011049Sbinkertn@umich.edu        if ticks is None:
4021049Sbinkertn@umich.edu            ticks = self.ticks
4031049Sbinkertn@umich.edu        sql = self.__dict__['get'](self, stat, bins, ticks)
4041049Sbinkertn@umich.edu        self.query(sql)
4051049Sbinkertn@umich.edu
4061049Sbinkertn@umich.edu        runs = {}
4071049Sbinkertn@umich.edu        for x in self.cursor.fetchall():
4081049Sbinkertn@umich.edu            data = Data(x)
4091049Sbinkertn@umich.edu            if not runs.has_key(data.run):
4101049Sbinkertn@umich.edu                runs[data.run] = {}
4111049Sbinkertn@umich.edu            if not runs[data.run].has_key(data.x):
4121049Sbinkertn@umich.edu                runs[data.run][data.x] = {}
4131049Sbinkertn@umich.edu
4141049Sbinkertn@umich.edu            runs[data.run][data.x][data.y] = data.data
4151049Sbinkertn@umich.edu        return runs
416