root/galaxy-central/eggs/Cheetah-2.2.2-py2.6-macosx-10.6-universal-ucs2.egg/Cheetah/Tools/MondoReport.py @ 3

リビジョン 3, 12.6 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1"""
2@@TR: This code is pretty much unsupported.
3
4MondoReport.py -- Batching module for Python and Cheetah.
5
6Version 2001-Nov-18.  Doesn't do much practical yet, but the companion
7testMondoReport.py passes all its tests.
8-Mike Orr (Iron)
9
10TODO: BatchRecord.prev/next/prev_batches/next_batches/query, prev.query,
11next.query.
12
13How about Report: .page(), .all(), .summary()?  Or PageBreaker.
14"""
15import operator, types
16try:
17    from Cheetah.NameMapper import valueForKey as lookup_func
18except ImportError:
19    def lookup_func(obj, name):
20        if hasattr(obj, name):
21            return getattr(obj, name)
22        else:
23            return obj[name] # Raises KeyError.
24
25########## CONSTANTS ##############################
26
27True, False = (1==1), (1==0)
28numericTypes = types.IntType, types.LongType, types.FloatType
29
30########## PUBLIC GENERIC FUNCTIONS ##############################
31
32class NegativeError(ValueError):
33    pass
34
35def isNumeric(v):
36    return type(v) in numericTypes
37
38def isNonNegative(v):
39    ret = isNumeric(v)
40    if ret and v < 0:
41        raise NegativeError(v)
42
43def isNotNone(v):
44    return v is not None
45
46def Roman(n):
47    n = int(n) # Raises TypeError.
48    if n < 1:
49        raise ValueError("roman numeral for zero or negative undefined: " + n)
50    roman = ''
51    while n >= 1000:
52            n = n - 1000
53            roman = roman + 'M'
54    while n >= 500:
55            n = n - 500
56            roman = roman + 'D'
57    while n >= 100:
58            n = n - 100
59            roman = roman + 'C'
60    while n >= 50:
61            n = n - 50
62            roman = roman + 'L'
63    while n >= 10:
64            n = n - 10
65            roman = roman + 'X'
66    while n >= 5:
67            n = n - 5
68            roman = roman + 'V'
69    while n < 5 and n >= 1:
70            n = n - 1
71            roman = roman + 'I'
72    roman = roman.replace('DCCCC', 'CM')
73    roman = roman.replace('CCCC', 'CD')
74    roman = roman.replace('LXXXX', 'XC')
75    roman = roman.replace('XXXX', 'XL')
76    roman = roman.replace('VIIII', 'IX')
77    roman = roman.replace('IIII', 'IV')
78    return roman
79
80
81def sum(lis):
82    return reduce(operator.add, lis, 0)
83   
84def mean(lis):
85    """Always returns a floating-point number.
86    """
87    lis_len = len(lis)
88    if lis_len == 0:
89        return 0.00 # Avoid ZeroDivisionError (not raised for floats anyway)
90    total = float( sum(lis) )
91    return total / lis_len
92
93def median(lis):
94    lis = lis[:]
95    lis.sort()
96    return lis[int(len(lis)/2)]
97
98
99def variance(lis):
100    raise NotImplementedError()
101   
102def variance_n(lis):
103    raise NotImplementedError()
104   
105def standardDeviation(lis):
106    raise NotImplementedError()
107   
108def standardDeviation_n(lis):
109    raise NotImplementedError()
110
111
112
113class IndexFormats:
114    """Eight ways to display a subscript index.
115       ("Fifty ways to leave your lover....")
116    """
117    def __init__(self, index, item=None):
118        self._index = index
119        self._number = index + 1
120        self._item = item
121
122    def index(self):
123        return self._index
124
125    __call__ = index
126
127    def number(self):
128        return self._number
129
130    def even(self):
131        return self._number % 2 == 0
132
133    def odd(self):
134        return not self.even()
135
136    def even_i(self):
137        return self._index % 2 == 0
138
139    def odd_i(self):
140        return not self.even_i()
141
142    def letter(self):
143        return self.Letter().lower()
144
145    def Letter(self):
146        n = ord('A') + self._index
147        return chr(n)
148
149    def roman(self):
150        return self.Roman().lower()
151
152    def Roman(self):
153        return Roman(self._number)
154
155    def item(self):
156        return self._item
157
158
159
160########## PRIVATE CLASSES ##############################
161
162class ValuesGetterMixin:
163    def __init__(self, origList):
164        self._origList = origList
165
166    def _getValues(self, field=None, criteria=None):
167        if field:
168            ret = [lookup_func(elm, field) for elm in self._origList]
169        else:
170            ret = self._origList
171        if criteria:
172            ret = filter(criteria, ret)
173        return ret
174
175
176class RecordStats(IndexFormats, ValuesGetterMixin):
177    """The statistics that depend on the current record.
178    """
179    def __init__(self, origList, index):
180        record = origList[index] # Raises IndexError.
181        IndexFormats.__init__(self, index, record)
182        ValuesGetterMixin.__init__(self, origList)
183   
184    def length(self):
185        return len(self._origList)
186
187    def first(self):
188        return self._index == 0
189       
190    def last(self):
191        return self._index >= len(self._origList) - 1
192
193    def _firstOrLastValue(self, field, currentIndex, otherIndex):
194        currentValue = self._origList[currentIndex] # Raises IndexError.
195        try:
196            otherValue = self._origList[otherIndex]
197        except IndexError:
198            return True
199        if field:
200            currentValue = lookup_func(currentValue, field)
201            otherValue = lookup_func(otherValue, field)
202        return currentValue != otherValue
203
204    def firstValue(self, field=None):
205        return self._firstOrLastValue(field, self._index, self._index - 1)
206
207    def lastValue(self, field=None):
208        return self._firstOrLastValue(field, self._index, self._index + 1)
209
210    # firstPage and lastPage not implemented.  Needed?
211
212    def percentOfTotal(self, field=None, suffix='%', default='N/A', decimals=2):
213        rec = self._origList[self._index]
214        if field:
215            val = lookup_func(rec, field)
216        else:
217            val = rec
218        try:
219            lis = self._getValues(field, isNumeric)
220        except NegativeError:
221            return default
222        total = sum(lis)
223        if total == 0.00: # Avoid ZeroDivisionError.
224            return default
225        val = float(val)
226        try:
227            percent = (val / total) * 100
228        except ZeroDivisionError:
229            return default
230        if decimals == 0:
231            percent = int(percent)
232        else:
233            percent = round(percent, decimals)
234        if suffix:
235            return str(percent) + suffix # String.
236        else:
237            return percent # Numeric.
238
239    def __call__(self): # Overrides IndexFormats.__call__
240        """This instance is not callable, so we override the super method.
241        """
242        raise NotImplementedError()
243
244    def prev(self):
245        if self._index == 0:
246            return None
247        else:
248            length = self.length()
249            start = self._index - length
250            return PrevNextPage(self._origList, length, start)
251
252    def next(self):
253        if self._index + self.length() == self.length():
254            return None
255        else:
256            length = self.length()
257            start = self._index + length
258            return PrevNextPage(self._origList, length, start)
259           
260    def prevPages(self):
261        raise NotImplementedError()
262       
263    def nextPages(self):
264        raise NotImplementedError()
265
266    prev_batches = prevPages
267    next_batches = nextPages
268
269    def summary(self):
270        raise NotImplementedError()
271
272
273
274    def _prevNextHelper(self, start,end,size,orphan,sequence):
275        """Copied from Zope's DT_InSV.py's "opt" function.
276        """
277        if size < 1:
278            if start > 0 and end > 0 and end >= start:
279                size=end+1-start
280            else: size=7
281
282        if start > 0:
283
284            try: sequence[start-1]
285            except: start=len(sequence)
286            # if start > l: start=l
287
288            if end > 0:
289                if end < start: end=start
290            else:
291                end=start+size-1
292                try: sequence[end+orphan-1]
293                except: end=len(sequence)
294                # if l - end < orphan: end=l
295        elif end > 0:
296            try: sequence[end-1]
297            except: end=len(sequence)
298            # if end > l: end=l
299            start=end+1-size
300            if start - 1 < orphan: start=1
301        else:
302            start=1
303            end=start+size-1
304            try: sequence[end+orphan-1]
305            except: end=len(sequence)
306            # if l - end < orphan: end=l
307        return start,end,size
308
309
310
311class Summary(ValuesGetterMixin):
312    """The summary statistics, that don't depend on the current record.
313    """
314    def __init__(self, origList):
315        ValuesGetterMixin.__init__(self, origList)
316       
317    def sum(self, field=None):
318        lis = self._getValues(field, isNumeric)
319        return sum(lis)
320
321    total = sum
322
323    def count(self, field=None):
324        lis = self._getValues(field, isNotNone)
325        return len(lis)
326       
327    def min(self, field=None):
328        lis = self._getValues(field, isNotNone)
329        return min(lis) # Python builtin function min.
330       
331    def max(self, field=None):
332        lis = self._getValues(field, isNotNone)
333        return max(lis) # Python builtin function max.
334
335    def mean(self, field=None):
336        """Always returns a floating point number.
337        """
338        lis = self._getValues(field, isNumeric)
339        return mean(lis)
340
341    average = mean
342
343    def median(self, field=None):
344        lis = self._getValues(field, isNumeric)
345        return median(lis)
346
347    def variance(self, field=None):
348        raiseNotImplementedError()
349
350    def variance_n(self, field=None):
351        raiseNotImplementedError()
352
353    def standardDeviation(self, field=None):
354        raiseNotImplementedError()
355
356    def standardDeviation_n(self, field=None):
357        raiseNotImplementedError()
358
359
360class PrevNextPage:
361    def __init__(self, origList, size, start):
362        end = start + size
363        self.start = IndexFormats(start, origList[start])
364        self.end = IndexFormats(end, origList[end])
365        self.length = size
366       
367
368########## MAIN PUBLIC CLASS ##############################
369class MondoReport:
370    _RecordStatsClass = RecordStats
371    _SummaryClass = Summary
372
373    def __init__(self, origlist):
374        self._origList = origlist
375
376    def page(self, size, start, overlap=0, orphan=0):
377        """Returns list of ($r, $a, $b)
378        """
379        if overlap != 0:
380            raise NotImplementedError("non-zero overlap")
381        if orphan != 0:
382            raise NotImplementedError("non-zero orphan")
383        origList = self._origList
384        origList_len = len(origList)
385        start = max(0, start)
386        end = min( start + size, len(self._origList) )
387        mySlice = origList[start:end]
388        ret = []
389        for rel in range(size):
390            abs_ = start + rel
391            r = mySlice[rel]
392            a = self._RecordStatsClass(origList, abs_)
393            b = self._RecordStatsClass(mySlice, rel)
394            tup = r, a, b
395            ret.append(tup)
396        return ret
397
398
399    batch = page
400
401    def all(self):
402        origList_len = len(self._origList)
403        return self.page(origList_len, 0, 0, 0)
404   
405   
406    def summary(self):
407        return self._SummaryClass(self._origList)
408
409"""
410**********************************
411    Return a pageful of records from a sequence, with statistics.
412
413       in : origlist, list or tuple.  The entire set of records.  This is
414              usually a list of objects or a list of dictionaries.
415            page, int >= 0.  Which page to display.
416            size, int >= 1.  How many records per page.
417            widow, int >=0.  Not implemented.
418            orphan, int >=0.  Not implemented.
419            base, int >=0.  Number of first page (usually 0 or 1).
420
421       out: list of (o, b) pairs.  The records for the current page.  'o' is
422              the original element from 'origlist' unchanged.  'b' is a Batch
423              object containing meta-info about 'o'.
424       exc: IndexError if 'page' or 'size' is < 1.  If 'origlist' is empty or
425              'page' is too high, it returns an empty list rather than raising
426              an error.
427       
428        origlist_len = len(origlist)
429        start = (page + base) * size
430        end = min(start + size, origlist_len)
431        ret = []
432        # widow, orphan calculation: adjust 'start' and 'end' up and down,
433        # Set 'widow', 'orphan', 'first_nonwidow', 'first_nonorphan' attributes.
434        for i in range(start, end):
435            o = origlist[i]
436            b = Batch(origlist, size, i)
437            tup = o, b
438            ret.append(tup)
439        return ret
440
441    def prev(self):
442        # return a PrevNextPage or None
443
444    def next(self):
445        # return a PrevNextPage or None
446
447    def prev_batches(self):
448        # return a list of SimpleBatch for the previous batches
449
450    def next_batches(self):
451        # return a list of SimpleBatch for the next batches
452
453########## PUBLIC MIXIN CLASS FOR CHEETAH TEMPLATES ##############
454class MondoReportMixin:
455    def batch(self, origList, size=None, start=0, overlap=0, orphan=0):
456        bat = MondoReport(origList)
457        return bat.batch(size, start, overlap, orphan)
458    def batchstats(self, origList):
459        bat = MondoReport(origList)
460        return bat.stats()
461"""
462
463# vim: shiftwidth=4 tabstop=4 expandtab textwidth=79
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。